Skip to content

Decide what acts on a superseded trust anchor before it becomes an outage #346

Description

@LKSNDRTMLKV

Decision 5 of #324, and the one with a date attached.

What exists

#321 added AnchorFreshness on a verified LOTL: Current, Superseded { lotl_names }, or Unknown. It is computed after the verdict and deliberately never part of it — a superseded pin keeps verifying until the Commission actually rotates the signing certificates, so folding it in would refuse documents that are perfectly good today.

verify_lotl_with logs a warning when it is not Current. That is the whole of the response. Nothing else reads it, and nothing calls verify_lotl at runtime yet.

Why this matters more than a warning suggests

The trust anchor is not a certificate authority. It is six SHA-256 digests taken from Official Journal notice 52026XC01944, compiled into the binary, and the Commission republishes that notice. Two facts follow:

  • refreshing the pin needs a release, not a configuration change — that is deliberate, because an operator who can repoint the anchor can make any list verify;
  • the certificate signing when it was pinned expires 2027-11-17. That is a calendar date, not a discovery.

A pin nobody refreshes eventually meets a LOTL signed by a certificate the notice no longer names. It fails closed, correctly, as LotlRejected::NotAnchored — and because step 1 of a refresh pass is verifying the LOTL, every national list then goes unrefreshed too. On a date nobody has in a calendar, the whole qualification surface goes dark and reads like an outage rather than a lapsed pin.

Superseded is the window between "a newer notice exists" and "the old certificates stop working", and it is the only chance to refresh without that happening.

What has to be decided

  1. Who sees it. A tracing::warn! is invisible to an operator who is not reading logs, and the people who need to act on this are (a) whoever cuts releases, because the fix is a release, and (b) the operator, because their node is on a clock. Candidates: the operator-wide seal route, a node health signal (Operators have no way to surface node-local health signals to an external monitor #138 is about exactly this gap), or a metric.

  2. Does it ever become a refusal? Presently no, and that is right. But there is a point — the pinned certificate's own notAfter — after which continuing to serve qualification verdicts from an anchor that has expired is arguably worse than refusing. verify_lotl's doc already notes the anchor check is identity, not validity: "the Official Journal is the authority for which keys may sign, and it is not a CRL". Whether a node should notice its own anchor's expiry is unanswered.

  3. What re-pins it. Today: a human reads the notice, computes six digests, and ships a release. Whether that is a documented runbook, a just recipe that fetches the notice and prints the digests, or a test that fails as the date approaches, is undecided. A test that starts failing before 2027-11-17 is the cheapest mechanism that cannot be forgotten, and this repository has the habit already — the_pinned_anchor_is_still_the_notice_in_force fails when the Commission republishes.

  4. Unknown is not Current. feat(seal): warn when the pinned anchor has been superseded #321 was careful about that, and whatever acts on this has to stay careful: a document naming no notice means the pin could not be checked, and treating it as fine is how a staleness signal goes quiet exactly when it is most needed.

Why it is deferred

The natural home for acting on this is the refresher — it is the thing verifying the LOTL on a schedule — and that does not exist yet (#345). Wiring an alarm to a code path nothing calls would be an alarm nothing can ring.

Not blocking, with an asterisk

Nothing here can produce a qualified seal, so the anchor is unused today. The asterisk is that 2027-11-17 arrives whether or not the feature is wired, and the cost of noticing late is a release under time pressure.

Related: #324 · #321 (the signal) · #345 (the refresher that would act on it) · #138 (node-local health signals)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    surface/sealMoves sealing, trusted lists or trust-service procurementtype/decisionNeeds a call; analysis alone will not close iturgency/backlogOwed, unscheduled

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions