2.0 KiB
Capability Spec: data-masking
Package: @suaveplan/data-masking
Version: 0.0.0 (genesis)
Status: ADDED
ADDED Requirements
DM-01 — Strategy contract
Every MaskingStrategy MUST expose { name, mask(value, options?): MaskResult }. Built-in strategies hash, partial, redact, maskEmail, maskPhone, maskIp, maskCreditCard MUST all implement this contract.
DM-02 — Registry
MaskingRegistry.register(name, strategy) MUST reject duplicates unless overwrite: true. MaskingRegistry.resolve(name) MUST throw DATA_MASKING.UNKNOWN_STRATEGY when the name is absent.
DM-03 — Idempotency
DataMasker.mask MUST be idempotent: mask(mask(x)) === mask(x) (structural equality) for every built-in strategy on PII inputs.
DM-04 — Type detection
TypeDetector.detect(value) MUST return an array of DetectionResult { type, start, end, confidence }. Built-in SensitiveDataType values MUST include email, phone, credit-card, ssn, ipv4, ipv6, jwt, api-key.
DM-05 — Conditional masking
ConditionalMasker.apply(value, ctx) MUST evaluate the MaskingPolicy with MaskingContext { role, permissions: FieldPermission[] }. Policies MUST either mask, allow, or redact per-field. Unknown policies MUST surface as DATA_MASKING.INVALID_POLICY.
DM-06 — Audit trail
MaskingAudit.record(entry) MUST write AuditEntry { at, actor?, field, strategy, outcome } to every registered AuditSink. Sink failures MUST be captured and surfaced as DATA_MASKING.AUDIT_SINK_FAILED without aborting the mask itself.
DM-07 — Credit-card mask
maskCreditCard MUST preserve the last 4 digits and validate Luhn; non-Luhn inputs MUST pass through unchanged (they're not actually credit cards) and record a lower-confidence detection result.
DM-08 — Observability
Every mask call MUST record data_masking.mask.duration_ms histogram and data_masking.masked.total{type} counter. Masked values MUST NOT appear in OTel attributes.