fix(cli): redact body values marked sensitive in diagnostics
Merged
2Y
10d ago+4696+4696+0123456789012345678901234567890123456789-28-28-01234567890123456789
Stacked on #72; review that first. This PR's base is fix/terraform-sensitive-response-logs.
Why
--dry-run and --debug redact body values only by name (password, token, client_secret, …). A value marked sensitive in the schema (x-speakeasy-param-sensitive: true or format: password) but carrying a generic name such as value or passphrase was printed in clear text, and so was a whole body whose schema carries the marker.
What changed
- Shared redaction: dry-run and debug previews pass request and response bodies through the embedded SDK's
redactpackage from #72 (redact.RequestBody/redact.ResponseBody) before applying the existing name-based preview rules. The SDK stamps the operation ID on each request context, so the schema graph is selected per SDK method, and split request content types each use their own graph. The CLI no longer builds its own request-body graph. - Responses: debug response previews now mask schema-marked values too; previously only name-based rules applied.
- Whole bodies: a body masked as a whole is shown as the mask (
(sensitive)) instead of a byte count when it no longer parses as its content type. - JSON-encoded form fields: name-based rules apply inside them, so a property named like a credential stays hidden next to a schema-marked one; a field with nothing to redact is shown exactly as sent.
- Schema-marked values read
(sensitive)(the shared mask); name-based redaction still reads[REDACTED]. - Docs: the CLI template README describes the redaction order and its limits (union variants are not told apart; a marker beside a
$refis not read). - Review SDK:
zSDKs/sdk-cli/internal/client/diagnostics.goregenerated.
Testing
- Primary fixture
cli-sensitive-body-fields.yaml: marked fields at the top level, nested, in array items and map values, through self and mutual recursion, discriminated unions (including a recursive variant in both member orders), multipart and form bodies with JSON-encoded fields (including an unmarkedpasswordbeside a marked field, and a marked property whose wire name ends in brackets), repeated scalar fields, split request content types (including an unmarked field that shares a marked field's name in another content type), whole bodies marked sensitive (JSON, form, multipart, text), sensitiveadditionalPropertiesbeside declared fields, a union of a sensitive array and a plain object, and a response with a marked field. TestDiagnosticsRedactSensitiveBodyFieldsruns each case under human dry-run, JSON dry-run and debug.TestDiagnosticsSensitiveBodyPreservesWireAndResponsechecks the server still receives the secrets;TestDiagnosticsKeepUnmarkedFieldSharingSensitiveNamechecks unmarked fields stay readable;TestDebugRedactsSensitiveResponseFieldschecks debug hides a marked response value while decoded output keeps it.TARGET=review make test-cli: 690 passed, 2 skipped.TARGET=primary make test-cli: 1889 tests; the only failures are the fourTestConfigure*tests, which depend on agent-mode detection being off and pass with the detection variables unset.
Public-safety check
- This change contains no credentials, customer documents, private repository URLs, private filesystem paths, or unredacted private logs.
- Title, body, comments, and commit messages name no customers or customer-derived identifiers, private paths or trackers, or workflow provenance, and are understandable without private context (
.claude/skills/public-repo-communication/SKILL.md). - Generated fixtures and review SDK changes are public-safe.
- I reviewed
git diff --check.