Documentation
¶
Overview ¶
Package privacy is the SOURCE-SIDE telemetry redaction classifier (A6, #627 — the A0.6 privacy half of #611). It is pure domain: given a field category and value it decides allow / redact / hash / drop, and Scrub applies a Policy to a telemetry envelope on the agent BEFORE the spool/ship, so unredacted secrets never persist or leave the host. Safe-by-default: no environment collected, bounded argv/path, and known secret patterns (tokens, keys, passwords, connection strings) redacted even inside otherwise-allowed fields. The policy is attributed by a distinct RedactionPolicyDigest recorded with the data — separate from the sampling policy digest.
Index ¶
Constants ¶
const RedactionPlaceholder = "[redacted]"
RedactionPlaceholder replaces a redacted value or secret span. It is a stable, distinctive ASCII marker so a reader (and a test) can tell redaction happened without guessing.
Variables ¶
This section is empty.
Functions ¶
func IsCredentialFlag ¶
IsCredentialFlag reports whether an argv element is a lone credential flag whose next element is a value to redact.
func RedactionPolicyDigest ¶
RedactionPolicyDigest is a deterministic, domain-separated identity for source-redaction behavior, recorded with scrubbed data so a reader knows exactly how it was redacted. It is DISTINCT from the sampling-policy digest. Human policy version labels are aliases around this content identity and are therefore excluded. The HashSalt is folded in as its own digest (not raw) so the identity is stable without echoing the salt into the commitment.
func SameAssignment ¶
func SameAssignment(left, right Assignment) bool
SameAssignment compares the declarative immutable policy-version identity. CreatedAt is server-owned admission metadata: insert-first stores preserve the first value when a client retries the same policy under a later server clock.
Types ¶
type Activation ¶
type Activation struct {
TenantID shared.ID `json:"tenant_id"`
OperationID shared.ID `json:"operation_id"`
Revision uint64 `json:"revision"`
PolicyDigest string `json:"policy_digest"`
PolicyVersion string `json:"policy_version"`
ActivatedBy string `json:"activated_by"`
ActivatedAt time.Time `json:"activated_at"`
}
Activation is one immutable active-policy pointer transition. Revision is monotonic per tenant, so A -> B -> A remains three independently auditable governance facts while an exact retry can recover the original transition.
func (Activation) Validate ¶
func (a Activation) Validate() error
type Assignment ¶
type Assignment struct {
TenantID shared.ID `json:"tenant_id"`
Policy Policy `json:"policy"`
Digest string `json:"digest"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
}
Assignment is an immutable tenant policy version. Active selection is stored separately so policy history remains append-only.
func NewAssignment ¶
func NewAssignment( tenantID shared.ID, policy Policy, createdBy string, now time.Time, ) (Assignment, error)
NewAssignment validates a source-safe policy and binds its immutable digest.
func (Assignment) Validate ¶
func (a Assignment) Validate() error
Validate verifies durable provenance and recomputes policy identity.
type FieldCategory ¶
type FieldCategory string
FieldCategory names a logical telemetry field the policy reasons about, so a policy is field-aware without coupling to concrete struct layouts.
const ( CategoryProcessArg FieldCategory = "process.arg" CategoryProcessPath FieldCategory = "process.path" CategoryProcessComm FieldCategory = "process.comm" // CategoryProcessEnv is reserved: the schema collects no environment today, and the default policy // drops it, so if an env field is ever added it is redacted-by-omission by default. CategoryProcessEnv FieldCategory = "process.env" CategoryFilePath FieldCategory = "file.path" CategoryFileComm FieldCategory = "file.comm" CategoryNetworkComm FieldCategory = "network.comm" CategoryPrivilegeComm FieldCategory = "privilege.comm" )
func (FieldCategory) Valid ¶
func (c FieldCategory) Valid() bool
type FieldDisposition ¶
type FieldDisposition string
FieldDisposition is what the policy does with a field's value.
const ( // DispositionAllow keeps the value, but (when Policy.RedactSecrets) still scrubs embedded secret // patterns — an allowed field is never a bypass for a token pasted into an argument. DispositionAllow FieldDisposition = "allow" // DispositionRedact replaces the whole value with the redaction placeholder. DispositionRedact FieldDisposition = "redact" // DispositionHash replaces the value with a keyed digest — correlation without the cleartext. DispositionHash FieldDisposition = "hash" // DispositionDrop removes the value entirely. DispositionDrop FieldDisposition = "drop" )
func (FieldDisposition) Valid ¶
func (d FieldDisposition) Valid() bool
Valid reports whether d is a known disposition.
type Policy ¶
type Policy struct {
// Dispositions maps a category to its disposition; a category absent here uses DispositionAllow.
Dispositions map[FieldCategory]FieldDisposition
// RedactSecrets scans allowed/redacted string values for known secret patterns and scrubs the matches.
RedactSecrets bool
// MaxArgLen / MaxArgCount bound argv so a pathological command line cannot exfiltrate unbounded data;
// MaxPathLen bounds a path. <=0 means unbounded for that dimension.
MaxArgLen int
MaxArgCount int
MaxPathLen int
// HashSalt keys the DispositionHash digest. It is NOT a secret store; it only prevents trivial
// dictionary correlation across policies. Same salt+value → same hash (correlation preserved).
HashSalt string
// Version is the immutable policy-version alias and lineage label. It is not part of the redaction-content digest.
Version string
}
Policy is a tenant-configurable source-side redaction policy. The zero value is NOT safe to use; call DefaultPolicy (or Normalize on a partially-built one) so caps and secret scanning are set.
func DefaultPolicy ¶
func DefaultPolicy() Policy
DefaultPolicy is the safe default: no environment collected, argv/path bounded, comms/paths/args allowed but secret-scanned. It never drops argv wholesale (that would destroy forensic value); instead it redacts only the secret spans within.
func (Policy) Classify ¶
func (p Policy) Classify(cat FieldCategory, value string) (string, FieldDisposition)
Classify applies the category's disposition to a single value and reports the disposition actually applied (an allowed value with a scrubbed secret reports DispositionRedact, so the caller can flag it).
func (Policy) RedactArgv ¶
RedactArgv redacts a whole argv slice as a unit (positions preserved). Each element is classified as a process arg (disposition + per-element secret scan), AND — the reason this is slice-aware — when an element is a lone credential flag its FOLLOWING element (the space-separated value) is redacted wholesale. It also handles command-scoped MySQL/MariaDB -pPASSWORD when argv[0] identifies that client. Source scrubbers additionally pass the authoritative Process.Path/Comm so this does not rely on argv[0].
func (Policy) ValidateSourceFloor ¶
ValidateSourceFloor enforces the non-relaxable source-privacy floor. Tenant policy may collect less data than the default, but it cannot enable process environments, disable known-secret scrubbing, or loosen argv/path bounds.
type Report ¶
type Report struct {
PolicyDigest string
Redacted int // values redacted, hashed, or secret-scrubbed
Dropped int // values dropped entirely
}
Report summarizes what a Scrub did, for honesty signals and tests. PolicyDigest is the RedactionPolicyDigest of the applied policy (also stamped onto the returned envelope).
func Scrub ¶
func Scrub(env telemetry.TelemetryEnvelope, policy Policy) (telemetry.TelemetryEnvelope, Report, error)
Scrub applies the policy to a telemetry envelope on the SOURCE side, returning a scrubbed copy (the input is never mutated — it operates on env.Clone()), a Report, and any error. It stamps the envelope's RedactionPolicyDigest and sets QualityRedacted when anything changed, so the redaction travels with the data. Callers apply it BEFORE the spool/ship so unredacted secrets never persist or leave the host.
func ScrubDetection ¶
ScrubDetection redacts a confirmed detection's EVIDENCE at the source (A6, #627) before it is persisted and shipped. A detection embeds the raw events that triggered it (argv, paths, comms), so without this a rule firing on a credential-bearing command line would ship the exact secret the telemetry path already scrubs — and, once sealed into the permanent evidence chain (A5), unredactably so. It returns a redacted DEEP COPY (the caller's Detection, still held by the engine, is never mutated) and a Report.
It applies the same field classifier and argv/path bounds as telemetry Scrub. Detection evidence has no\n// per-field truncation-honesty flags, but its evidence is already bounded by the rule window.