Skip to content

feat: add explicit withheld signal to OutputScanResult for WithholdPolicy #284

@Aureliolo

Description

@Aureliolo

Context

During PR #280 review, Copilot flagged that WithholdPolicy sets redacted_content=None to trigger ToolInvoker's fail-closed branch, but the invoker currently logs this as "no redacted content available" — which is misleading when redaction was available but was intentionally withheld by policy.

Problem

The ToolInvoker cannot distinguish between:

  1. No redacted content available (scanner couldn't produce a redacted version)
  2. Content intentionally withheld by policy (WithholdPolicy cleared it)

Both cases result in has_sensitive_data=True + redacted_content=None, but the semantics differ.

Proposed Enhancement

Add an explicit signal to OutputScanResult so the invoker can log/report the correct reason:

Option A: Add a withheld: bool = False field to OutputScanResultWithholdPolicy sets it to True.

Option B: Add an outcome enum field (e.g. redacted, withheld, passed_through, log_only) that policies set.

Option C: Use a sentinel string (e.g. "[WITHHELD BY POLICY]") — but this defeats fail-closed since the invoker would use the string.

Option B is likely cleanest as it scales to all policies, but requires updating all consumers of OutputScanResult.

Impact

  • OutputScanResult model (new field)
  • All 4 policy implementations (set the new field)
  • ToolInvoker (use the field for logging/metrics)
  • Tests across security and tools modules

Origin

Review comment from Copilot on PR #280: #280 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    prio:highImportant, should be prioritizedspec:securityDESIGN_SPEC Section 12 - Security & Approval Systemspec:toolsDESIGN_SPEC Section 11 - Tool & Capability Systemtype:featureNew feature implementation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions