Control template: no sensitive data in logs
A CALM control that flags PRs introducing a log statement (or any added line) containing forbidden field names. Customer-authored; ArchRails enforces it via the constraint engine. No regex maintenance on our end, no opinionated key list — the customer owns the vocabulary.
When to use it
- You handle client / patient / cardholder PII or PCI data.
- You want a hard blocker on any PR that introduces a logger call (or any code line) referencing the fields you've enumerated.
- You want the verdict's vocabulary to be yours (
tax_id,customer_email,member_id) rather than ArchRails' canonical list.
The snippet
Add this controls block to whichever node(s) own the code paths you
care about (typically your service node):
{
"unique-id": "<your-service-node>",
"node-type": "service",
"name": "<Service Name>",
"controls": {
"no-pii-in-logs": {
"description": "<Customer-authored description. The framer LLM uses this verbatim when explaining a violation — make it your policy language, not ours.>",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/no-pii-in-logs",
"config": {
"control-id": "no-client-pii",
"name": "No client PII in plaintext logs",
"description": "Applies to all log statements in <your-service-node>.",
"forbidden-fields": [
"email",
"full_name",
"ssn",
"tax_id",
"postal_address",
"account_number",
"card_number"
]
}
}
]
}
}
}
Tune forbidden-fields to your actual schema. Common additions by
industry:
- Healthcare:
patient_id,mrn,dob,medical_record_number - Banking / PCI:
pan,cvv,iban,routing_number - Telecom:
imsi,imei,msisdn - HR:
employee_id,home_address,tin
What ArchRails does
The constraint engine enforces every entry in forbidden-fields
as a banned token. When a PR adds a line where any of those field
names literally appears (case-insensitive, identifier-boundary match),
the engine fires a violation with:
control_id: your control's alias (e.g.no-pii-in-logs)path: the file that introduced the linesummary/why_it_matters/suggested_fix: framer prose grounded in yourdescriptionfield — not training-data boilerplate
This control fires at both MCP-time (in your agent's IDE before code ships) and PR-time (on the merge gate). Same engine, same verdict.
What it does NOT cover (and what to do instead)
This control matches identifier names, not
literal-value patterns. So an SSN-shaped literal hardcoded into a
log call (logger.info("test ssn 123-45-6789")) won't be caught unless
the field name ssn or similar appears in the same line.
Literal-value detection (SSN format, card-like digit runs, JWT tokens, Bearer headers, PEM blobs) is on the roadmap. Until that ships, secret-scanning tools (Snyk, GitGuardian, TruffleHog) are the recommended complement — ArchRails doesn't try to be a secret scanner.
Why customer-authored beats a hardcoded scanner
Because the forbidden-field list, the violation prose, and the attach points are all yours, the audit trail reads as your policy enforced your way — not as a third-party opinion enforced on you. False-positive tuning is editing your CALM, not filing a vendor ticket. Scope is the nodes you attach it to, not every file in the repo.