Skip to content

fix(output): apply finding redactions alongside secrets - #157

Merged
chiruu12 merged 2 commits into
UnplugAI:devfrom
chirag-gamer:fix/output-redaction-findings
Aug 24, 2026
Merged

fix(output): apply finding redactions alongside secrets#157
chiruu12 merged 2 commits into
UnplugAI:devfrom
chirag-gamer:fix/output-redaction-findings

Conversation

@chirag-gamer

@chirag-gamerchirag-gamer commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes#122

OutputPipeline now combines the existing secret sanitizer with policy-driven span redaction for output findings. Flagged URLs and other eligible non-secret findings no longer survive in redacted_text, while registered-secret and canary redaction stay covered.

Checklist

  • The issue this closes was assigned to me (see CONTRIBUTING.md)
  • This is my only open PR (one issue at a time, see CONTRIBUTING.md)
  • Target branch is dev (see BRANCHING.md)
  • cd sdk && make check-ci passes locally
  • New code has tests (every module gets a test file)
  • Public API changes are reflected in sdk/README.md / sdk/docs/
  • No secrets, internal URLs, or private paths in the diff
  • If a model wrote a meaningful part of this, I said so below (AI_POLICY.md)

Notes for reviewers

Finding spans are applied against the original text before any length-changing secret sanitization. When a finding overlaps a sanitizer-detected secret span, the secret interval is subtracted from the finding span: each remaining original-coordinate segment gets policy redaction ([BLOCKED:urls], strip, or the scanner replacement), and the secret itself keeps its named [REDACTED:<name>] placeholder from the sanitizer.

Tests added: issue repro through Guard().scan_output(), secret-before-URL ordering, a registered fake secret inside a URL finding under BLOCKED_TAGS / STRIP / REDACTED_TAGS, a leakage finding, NONE mode, and unit coverage for the span-splitting helper with two disjoint secret regions.

Verified locally: full pytest -q (1139 passed), ruff check + format, mypy, doc drift check, uv lock --check, scenario replays, attack gate, and exfil demo integration. unplug-audit reports 9/11 both with and without this change; the two failures are ML-model-not-configured on this machine, unrelated to the diff. No public API or docs change needed.

AI disclosure: Drafted with AI assistance; I reviewed the diff and ran the listed checks.

@greptile-apps

greptile-appsBot commented Aug 24, 2026

Copy link
Copy Markdown

Greptile Summary

The output pipeline now combines policy-driven finding redaction with secret sanitization while preserving named secret placeholders.

  • Subtracts detected secret spans from overlapping findings and redacts all remaining portions against the original text.
  • Applies secret sanitization after span redaction to avoid offset shifts.
  • Adds integration and unit coverage for overlapping spans and all supported redaction modes.

Confidence Score: 5/5

The pull request appears safe to merge.

No blocking failure remains.

Important Files Changed

FilenameOverview
sdk/src/unplug/pipelines/output.pyCombines policy span redaction with secret sanitization and correctly retains redaction coverage around overlapping secret spans.
sdk/tests/integration/test_guard_v2.pyAdds end-to-end coverage for output findings, secret ordering, overlap handling, and configured redaction modes.
sdk/tests/unit/pipelines/test_pipelines.pyVerifies finding-span subtraction for disjoint, covering, empty, and invalid secret spans.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Original output] --> B[Detect secret spans]
B --> C[Subtract secret spans from findings]
C --> D[Apply policy redaction to residual spans]
D --> E[Sanitize preserved secrets]
E --> F[Protected redacted_text]
Loading

Reviews (2): Last reviewed commit: "fix(output): preserve redaction around s..." | Re-trigger Greptile

Comment threadsdk/src/unplug/pipelines/output.py

@chiruu12chiruu12 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repros on dev: scan_output flags an ip_literal_url and an email, then returns redacted_text identical to the input, because the sanitizer branch dropped the findings entirely. Since Guard always constructs a SecretsSanitizer, that branch is the only one that ever ran, so url/pii/leakage redaction was dead in scan_output.

On this branch both get replaced, and a registered secret sitting inside a url span still comes out as [REDACTED:<name>] with the surrounding span redacted around it.

984 unit + integration pass (the two tests/unit/ml/test_model_store.py failures are present on dev as well and are unrelated), 178 security pass, ruff check and format clean.

Approving.

@chiruu12
chiruu12 merged commit cf0b0c7 into UnplugAI:devAug 24, 2026
7 checks passed
Sign up for freeto 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.

Output redaction ignores non-secret findings (URLs survive in redacted_text)

2 participants

@chirag-gamer@chiruu12