Raxx · internal docs

internal · gated ↑ index

Audit CI Gates

Status: Live — SC-A17 gate active as of #1497 Owner: devops / security Date: 2026-05-17 UTC


Overview

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.


SC-A17 — Audit action namespace allowlist gate

Purpose

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.

Scope

The gate scans the following source trees on every PR that touches them:

Files matching test_*.py and the argparse entry-point files (cli.py, conftest.py) are excluded.

Allowlist config file

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

What the gate checks

scripts/ci/check_audit_action_allowlist.py is run by the CI job audit-action-allowlist in .github/workflows/ci-pr.yml.

  1. Scans all .py source files under the configured directories.
  2. Finds every occurrence of action="<value>" or action='<value>' that is NOT on a pure-comment line.
  3. Looks up each <value> in docs/architecture/audit/action-allowlist.txt.
  4. Fails the pipeline with an error message naming the unregistered string and the exact file + line number.

The gate passes if all found action strings are registered.

Registering a new action

  1. Add the action string to docs/architecture/audit/action-allowlist.txt under the appropriate category comment.
  2. Document the action's purpose, actor class (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).
  3. Open a PR with both the source change and the allowlist entry. The CI gate on that PR will then pass.
  4. Get sign-off from the code reviewer that the action string is appropriate for the audit dimension and field allowlist.

Escape hatch

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:

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).

CI job name

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/**.


Future gates (planned)

Gate Status Card
SC-A17 (this gate) Live #1497
iOS companion app action namespace lint Post-launch Deferred