Read this first
The post-quantum mandates are dated: CNSA 2.0 and NIST IR 8547 name the years classical public-key cryptography becomes deprecated and then disallowed. `qscan --mandate <regime>` turns those dates into a CI gate: every classical public-key finding is mapped to the regime's clause and deadline, the gate warns once the deprecate date passes, and it fails the build once the disallow date passes — with `--lead-months` to fail early and `--policy` to fold in your organization's own crypto policy. Crucially, the gate is evaluated on pre-baseline findings: a severity baseline can accept existing debt, but it cannot make a regulatory deadline go away.
Most cryptography gates in CI answer one question: did this change add new classical crypto? That is the right question for stopping the debt from growing — the GitHub Action's default severity gate with a `--baseline` does exactly that — but it says nothing about the debt you already have. Compliance mandates ask a different question: will the cryptography you are running be permitted on the dates the regime names? Those are different gates, and conflating them is how organizations arrive at a disallow deadline with a green pipeline and a non-compliant estate.
Two gates, two questions
The severity gate is change-oriented. You accept the current findings into a baseline, and from then on the build fails only on new findings — post-quantum readiness becomes a ratchet that never slips backward. The mandate gate is calendar-oriented. It is evaluated against the findings before the baseline is applied, because the regulator does not care when a finding first appeared: RSA key exchange that predates your baseline is exactly as disallowed after the deadline as RSA added yesterday. In `qscan`, `--baseline` therefore suppresses findings for the severity gate only; `--mandate` sees the full pre-baseline set. A regulatory deadline cannot be baselined away.
Dated clauses, not vibes
The gate enforces the specific dated clauses of a regime, not a generic "PQC is coming" warning. Two regimes are supported today:
- `cnsa-2.0` — the NSA's CNSA 2.0 milestones for national security systems: classical public-key algorithms are deprecated and the first wave of requirements lands in 2030, and they are disallowed by 2033.
- `nist-ir-8547` — the federal transition timeline in NIST IR 8547: RSA, ECDSA, ECDH and their kin are deprecated after 2030 and disallowed after 2035.
The two calendars are not interchangeable. CNSA 2.0's 2033 disallow date is two years earlier than IR 8547's 2035 — an estate that plans against the federal timeline while actually serving national security systems is quietly two years behind. Pick the regime that genuinely governs you, and if both apply, gate on the earlier one.
How the gate escalates
The gate is deadline-aware rather than binary. Every prohibited finding is always reported with the clause it violates and the deadline attached to it, so the mapping is visible long before it bites. What changes over time is the consequence: once a regime's deprecate date passes, matching findings escalate to warnings; only once the disallow date passes does the gate fail the build. Two flags tighten the schedule. `--lead-months <n>` pulls the failure forward — inside the final n months before a disallow deadline, the gate fails early instead of warning, buying migration time while it still exists. `--fail-now` skips the calendar entirely and fails on any mandate-prohibited finding today, which is how teams that want the end-state behavior immediately run it.
Set lead time from your migration time, not from optimism
The honest value for `--lead-months` is your migration time — the Y in Mosca's X + Y > Z, the same quantity that drives the migration roadmap. If replacing a classical key exchange across your estate takes 18 months, a gate that starts failing 3 months before the disallow date is theater: it fires long after the last responsible moment to start. Work backward from the deadline through your real remediation time, and let CI fail while the fix is still schedulable.
Compose your organization's policy
Mandates are floors, not your whole crypto policy. `--policy <file>` layers an organization-level policy document over the regime: algorithm families your organization explicitly permits, or has formally scheduled for transition, are acknowledged in the output and exempted from the early gate — the warnings and lead-window failures that exist to create urgency you have already planned for. What the policy cannot do is override the regime's own end date: once a disallow deadline has passed, a matching finding fails the build regardless of what the policy file says. An organization can decide how it gets to compliance; it cannot self-exempt from a dated regulatory prohibition.
Wiring it into CI
The same gate is exposed as first-class inputs on the GitHub Action: `mandate`, `lead-months`, `fail-now`, and `policy` mirror the CLI flags. A realistic workflow is short — a checkout step followed by the scan action with `mandate: nist-ir-8547` (or `cnsa-2.0`), a `lead-months` value derived from your migration time (say `18`), and `policy` pointing at a committed crypto-policy file such as `.qscan/crypto-policy.json`. Teams that want the strict end-state from day one set `fail-now: true` instead of a lead window. Because the policy file lives in the repository, the exemptions are code-reviewed like everything else — which is the point of policy as code: the decision about what is acceptable is versioned, diffable, and attributable, not a setting someone once toggled in a dashboard.
Verdicts you can hand to an auditor
A gate that only flips exit codes is thin evidence. The mandate verdict rides in every machine-readable output: `--format json` carries a `mandateMapping` block tying each finding to its clause and deadline, the SARIF output records the verdict under `run.properties.mandate` so code-scanning dashboards can surface it, and the ISO/IEC 27001 A.8.24 `evidence` report is date-pinned and hashed — a point-in-time record that on this date, against this regime, this codebase produced this verdict. That is the artifact an auditor actually wants: not an assertion of compliance, but a reproducible mapping from findings to dated clauses.
What the gate does and does not assert
One honest boundary. The mandate gate enforces dated, family-level rules — it catches classical RSA, ECDH, ECDSA, DSA and their kin that a regime is retiring, on the regime's calendar. It does not yet assert post-quantum parameter levels: it will not tell you that a regime expects ML-KEM-1024 where you deployed ML-KEM-768. Retiring the classical families is the bulk of what the dated clauses demand, and it is what this gate makes enforceable today; parameter-level conformance remains a review-and-audit concern rather than a CI verdict.
How quantakrypto helps
The gate is only as good as the estate it can see and the plan behind it. Our audit builds the cryptographic inventory the scanner's findings are measured against, and establishes which regime — CNSA 2.0, IR 8547, or both — actually governs each system. A migration engagement turns the mandate calendar into the sequenced roadmap that makes the lead window achievable rather than aspirational, and helps you author the crypto-policy file so the exemptions reflect real transition plans. And training leaves your engineers able to read a mandate verdict — clause, deadline, lead window — and know what to do about it without a consultant in the loop.