Status: Live — SC-A17 gate active as of #1497 Owner: devops / security Date: 2026-05-17 UTC
The audit CI gates enforce that every audit event emitted by the application is documented and registered before it reaches production. This is the CI companion to SC-A3's runtime allowlist enforcement.
Every action= string literal passed to write_audit() or
write_audit_strict() in application code must appear in the registered
allowlist before the PR can merge. This prevents undocumented audit events
from silently entering the audit log where they would break the HMAC chain
integrity (SC-A11) or violate the SOC-2 auditability invariants.
The gate scans the following source trees on every PR that touches them:
backend_v2/console/velvet/reasonator/Files matching test_*.py and the argparse entry-point files (cli.py,
conftest.py) are excluded.
docs/architecture/audit/action-allowlist.txt
This is the same file consulted by SC-A3's runtime writer for field-level
allowlists. The CI gate reads only the action name lines; the runtime uses
the full per-action before_state/after_state field sets defined separately
in the writer service.
Format: one action string per non-comment line. Lines beginning with # are
comments. Blank lines are ignored. Action strings use the convention:
domain.noun.verb
Examples:
console.flag.flip
session.revoke
vault.rotation.completed
scripts/ci/check_audit_action_allowlist.py is run by the CI job
audit-action-allowlist in .github/workflows/ci-pr.yml.
.py source files under the configured directories.action="<value>" or action='<value>' that is
NOT on a pure-comment line.<value> in docs/architecture/audit/action-allowlist.txt.The gate passes if all found action strings are registered.
docs/architecture/audit/action-allowlist.txt
under the appropriate category comment.dimension), and permitted
before_state/after_state fields in the writer service's schema
documentation (ask the security-agent or open a design card if uncertain).In rare cases where a line must use a dynamic or transitional action string that cannot yet be registered (e.g., a migration helper that is removed in the same PR), add the escape-hatch comment to the same source line:
write_audit(action="temp.migration.helper") # audit-action-ok
Requirements for using the escape hatch:
# audit-action-ok as a comment on the same line
as the action= call.The escape hatch is visible in the CI output:
NOTE: 1 action string(s) suppressed via # audit-action-ok:
console/app/services/migration_helper.py:42 action='temp.migration.helper' [suppressed]
The --strict flag on the script treats suppressed lines as failures (used in
full audits, not normal PR CI).
audit-action-allowlist — required status check in branch protection for
main. The job is path-filtered: it only runs when a PR touches files in
backend_v2/**, console/**, velvet/**, or reasonator/**.
| Gate | Status | Card |
|---|---|---|
| SC-A17 (this gate) | Live | #1497 |
| iOS companion app action namespace lint | Post-launch | Deferred |