Skip to content

feat(workflows): make the privacy-shield test template real - #2500

Open
Hoang130203 wants to merge 1 commit into
Osmantic:mainfrom
Hoang130203:feat/n8n-privacy-shield-workflow
Open

feat(workflows): make the privacy-shield test template real#2500
Hoang130203 wants to merge 1 commit into
Osmantic:mainfrom
Hoang130203:feat/n8n-privacy-shield-workflow

Conversation

@Hoang130203

Copy link
Copy Markdown

Summary

config/n8n/privacy-shield-test.json was a placeholder — manualTrigger +
sticky note + "connections": {} — behind a catalog card advertising "Send a
test payload through Privacy Shield and verify PII is redacted"
.

For a privacy product, a compliance-check template that does nothing is a
particularly bad one to leave empty: the whole point is letting an operator
prove the shield is on before they trust it with real conversations.

Run Test
  -> Sample With PII        (email, US phone, SSN, IPv4 in one prompt)
  -> Through Privacy Shield (POST privacy-shield:8085/v1/chat/completions)
  -> Compliance Report      (verdict from the response headers)

The report reads the two headers proxy.py sets on every response:

response_headers.update({
    "X-Privacy-Shield": "active",
    "X-PII-Scrubbed": str(metadata.get("pii_count", 0)),
    ...
})

and turns them into something an operator can act on:

Condition Verdict
X-PII-Scrubbed > 0 PASS — the shield redacted before the model saw the prompt
X-PII-Scrubbed == 0 FAIL — nothing was redacted; check PRIVACY_SHIELD in .env
status ≥ 400 ERROR — check the credential and that privacy-shield is running

It also surfaces restored_reply, so you can see the shield putting the real
values back on the way in — the round trip, not just the redaction.

Choices worth reviewing

  • fullResponse: true because the evidence is in the headers, not the
    body. neverError: true so a 401 produces a readable verdict instead of
    a red node and a stack trace — this is a diagnostic workflow, so a failed
    request is a result, not a crash.
  • No key in the file. The request uses a generic Header Auth
    credential; the sticky note walks through creating it from SHIELD_API_KEY
    in .env. The node shows as needing a credential until the user picks one.
    I would rather that one-time step than ship a file with a secret-shaped
    placeholder in it.
  • The sample deliberately uses four types PII_COVERAGE.md documents as
    detected, and the note points at that file so an operator does not read a
    PASS as "everything is covered".

AI Assistance

AI assisted with drafting the node graph, the verdict wording, and this
description. I read proxy.py to confirm the header names and the fact that
they are set on every response, and validated the file against the real node
package before pushing.

Release Lane

  • Stable hotfix targeting release/2.6.x
  • Mainline change targeting main
  • Next-minor work targeting the next feature/minor release
  • Not sure; reviewer should help classify

Stable hotfix reason:

n/a

Changed Surface

  • Docs only
  • Tests only
  • Dashboard UI
  • Dashboard API / host agent
  • Installer / bootstrap / lifecycle
  • Docker Compose / service manifests
  • Model routing / Hermes / capabilities
  • Network exposure / auth / proxy
  • Dependencies / runtime wiring

(One JSON file under config/n8n/. An import payload for n8n; no ODS code
executes it. The catalog entry is unchanged.)

Risk And Validation

  • Risk level: Low
  • Validation run:
    • git diff --check
    • Markdown/link sanity for docs
    • Focused tests listed below
    • Dashboard lint/test/build
    • Extension audit / compose validation
    • Release-grade fleet or scoped hardware validation
    • Stable-lane patch validation, if targeting release/2.6.x

Commands/results:

# Validated against the exact node package ODS ships (n8n 2.6.4 -> 2.6.2).

$ node verify.js privacy-shield-test.json
n8n-nodes-base version: 2.6.2
node types loaded: 417
  checked privacy-shield-test.json: 5 nodes

ALL WORKFLOWS VALID

# Header names confirmed in the service source, not assumed:
$ grep -n "X-PII-Scrubbed\|X-Privacy-Shield" extensions/services/privacy-shield/proxy.py
354:            "X-Privacy-Shield": "active",
355:            "X-PII-Scrubbed": str(metadata.get("pii_count", 0)),

# Auth parameter values confirmed against the node definition:
#   authentication  -> none | predefinedCredentialType | genericCredentialType

Caveat: Docker is not running on my dev host, so I could not run this
against a live privacy-shield and watch a real X-PII-Scrubbed come back.
Static validation proves the file imports and every parameter is real; the
header names and the port come from the service source and manifest. Happy to
get a live run before you merge.

Operational Change Check

An import payload for n8n. Nothing in the installer, compose stack, ods-cli,
or dashboard-api executes it. Running it sends one chat completion through the
user's own shield — no external calls, no state written.

  • This is not an operational change.
  • This is an operational change and validation is recorded above.
  • This is an operational change and validation is intentionally deferred for:

Notes For Reviewers

The sample prompt contains fake PII by design. dana.reyes@example.com,
555-123-4567, 123-45-6789, 192.168.1.100 — reserved/example values, the
same ones pii_scrubber.py's own tests use. Nothing real, and nothing leaves
the machine either way.

One thing worth deciding. A PASS here means the shield redacted these four
types
. It does not mean coverage is complete — PII_COVERAGE.md is explicit
that names, addresses and non-16-digit cards are not detected. The note says
so, but if you would rather the verdict string itself carry that caveat, tell
me the wording you want.

Related: #2363 fixes the api_key pattern missing the spaced API Key: form,
and #2369 corrects PII_COVERAGE.md, which this note links to. Independent
changes.

Part of the series making the 18 stub templates real: #2496, #2497, #2498,
#2499.

config/n8n/privacy-shield-test.json was a manualTrigger plus a sticky
note saying "Customize the nodes below to match your setup", with
"connections": {} — an empty canvas behind a catalog card advertising
"Send a test payload through Privacy Shield and verify PII is redacted".

Now it does that:

    Run Test -> Sample With PII -> POST privacy-shield:8085
                                     /v1/chat/completions
             -> Compliance Report

The sample prompt carries an email, a US phone number, an SSN and an IPv4
address — four of the types PII_COVERAGE.md documents. The report node
reads the X-PII-Scrubbed and X-Privacy-Shield response headers the proxy
sets on every response and turns them into a verdict:

  >0 scrubbed  PASS — the shield redacted before the model saw the prompt
   0 scrubbed  FAIL — check PRIVACY_SHIELD in .env
     4xx/5xx   ERROR — check the credential and that the service is up

fullResponse is on because the evidence is in the headers, not the body,
and neverError is on so a 4xx produces a readable verdict instead of a
red node with a stack trace.

The request authenticates with a generic Header Auth credential rather
than a key baked into the file. The sticky note walks through creating it
from SHIELD_API_KEY in .env — the node will show as needing a credential
until the user picks one, which is the intended one-time setup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant