redact

package
v0.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

README

pkg/redact — payload redaction pipeline

A regex + exact-value scrubbing pipeline that removes credential-shaped content from payloads (agent output, relay diagnostics, anything body-adjacent). It is payload hygiene machinery only — it knows nothing about how secrets are stored or delivered.

Static pipeline (16 rules)

Applied in order by NewRedactor (see redact.go for the authoritative list): URL-embedded credentials, Bearer tokens, GitHub tokens, JSON "password": values, password=/token=/secret=/api[_-]key=/ x-api-key: assignments, PEM private keys, age keys, sk- keys, AWS access keys, JWTs, authorization: headers, and long base64 blobs. Extra patterns can be layered via NewRedactor(extra) or a JSON config file (NewRedactorFromFile; the agent-side default path is /sandbox-cfg/redact-patterns.json, absent → defaults only).

Static behavior is pinned byte-exact by the golden corpus in redact_dynamic_test.go (TestStaticPipelineGolden, one row per rule).

Dynamic rules (staged-key surface, 2026-09-17)

RegisterDynamic(rules ...DynamicRule) / UnregisterDynamic(id) manage exact-value rules — byte-exact literal matches (no regex metacharacters), grouped by ID: registering an existing ID replaces its group atomically; unregistering removes it. Rules are goroutine-safe against concurrent Redact.

Two invariants:

  1. Dynamic rules run before the static pipeline, longest value first. A static pattern (e.g. token=…) could otherwise fragment a secret before the exact match sees it, and a registered value that prefixes another registered value could fragment the longer one — ordering by descending value length keeps removal atomic and output deterministic. Pinned by TestDynamicPrefixOverlapAtomicAndDeterministic.
  2. Static behavior never changes when dynamic rules are registered — pinned by the golden corpus run in both modes.

The primary consumer is the relay-key staging provider (pkg/secrets/staging_provider.go, design 0058 §4.9): at seal and resolve time it registers the staged key material (raw, standard-base64, and URL-base64 encodings) under an envelope-derived rule-group ID, and the router's sanitization stage (US-72.2) applies the combined pipeline to proxied traffic so a key can never be echoed back through the relay. Revocation (Secret deletion) unregisters the group.

Consumers

Consumer Use
cmd/workspace-agentd agent-output scrubbing + the redact subcommand (the former cmd/redact binary, folded in #1152 / design 0053 S2, #1116)
pkg/secrets (staging provider) dynamic staged-key registration (seal/resolve seam)

Home: stays in pkg/. Issue #842 once planned relocating it into cmd/redact; that binary has since been folded into workspace-agentd, and with the staging provider as a second genuine consumer the package is shared platform machinery, not a CLI internal.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Redact

func Redact(input string) (string, error)

func RegisterDynamic added in v0.33.0

func RegisterDynamic(rules ...DynamicRule) error

RegisterDynamic registers exact-value rules on the package-level redactor (the shared pipeline agents and the relay router consume). See (*Redactor).RegisterDynamic for semantics.

func UnregisterDynamic added in v0.33.0

func UnregisterDynamic(id string)

UnregisterDynamic removes a rule group from the package-level redactor.

Types

type DynamicRule added in v0.33.0

type DynamicRule struct {
	ID          string
	Value       string
	Replacement string
}

DynamicRule is an exact-value redaction rule. Unlike the static regex pipeline, the Value is matched literally (no regex metacharacter interpretation) and byte-exactly, so arbitrary key material — including non-UTF-8 bytes — can be registered as a rule. Rules are grouped by ID: RegisterDynamic replaces any existing group with the same ID, and UnregisterDynamic removes the whole group.

Consumers with exact secret material (e.g. the relay-staging provider, which is the one place the platform legitimately knows a staged key's plaintext at seal/resolve time) register rules at the moment the material is known and unregister on revocation.

type Pattern

type Pattern struct {
	Regex       string `json:"regex"`
	Replacement string `json:"replacement"`
}

type Redactor

type Redactor struct {
	// contains filtered or unexported fields
}

func NewRedactor

func NewRedactor(extraPatterns []Pattern) (*Redactor, error)

func NewRedactorFromFile

func NewRedactorFromFile(path string) (*Redactor, error)

func (*Redactor) DynamicRules added in v0.34.2

func (r *Redactor) DynamicRules() []DynamicRule

DynamicRules snapshots the registered dynamic rules (dynamic longest-first order). The BYO resolve router (US-72.2) uses it to apply the precise exact-value staged-key rules to proxied bodies — bodies get dynamic-only redaction (the static heuristics would corrupt legitimate structured/vision payloads, e.g. long base64 image parts); diagnostics and logs get the full pipeline via Redact (design 0058 §4.9, K7).

func (*Redactor) Redact

func (r *Redactor) Redact(input string) (string, error)

func (*Redactor) RedactDynamicOnly added in v0.34.2

func (r *Redactor) RedactDynamicOnly(input string) string

RedactDynamicOnly applies exactly the dynamic exact-value rules (no static pipeline) — see DynamicRules for why the router's body path uses this surface.

func (*Redactor) RegisterDynamic added in v0.33.0

func (r *Redactor) RegisterDynamic(rules ...DynamicRule) error

RegisterDynamic adds exact-value rules, grouped by ID. Registering with an ID that already exists atomically replaces that ID's rules — rotation and re-registration are idempotent. Validation failures apply no partial state.

func (*Redactor) UnregisterDynamic added in v0.33.0

func (r *Redactor) UnregisterDynamic(id string)

UnregisterDynamic removes every rule in the named group. Unknown IDs are a no-op.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL