Skip to content

Report which of fog.enrollsb's three exits was actually reached - #166

Open
mastacontrola wants to merge 1 commit into
masterfrom
report-secureboot-enrolment-outcome
Open

Report which of fog.enrollsb's three exits was actually reached#166
mastacontrola wants to merge 1 commit into
masterfrom
report-secureboot-enrolment-outcome

Conversation

@mastacontrola

Copy link
Copy Markdown
Member

Companion to FOGProject/fogproject#1451. That PR adds a per-host Secure Boot and enrolment ledger; this is the half only FOS can supply.

The problem

fog.enrollsb has three exits and every one of them ends with the same argument-free . /bin/fog.nonimgcomplete, so from the server all three look identical — the task completed. They are not remotely the same thing:

db the machine was in Setup Mode, db was written, it is enrolled
trusted it already trusted this certificate; nothing was enrolled here, and nothing observed how the trust got there
mok a request was staged. The machine is not enrolled and will not boot with Secure Boot on until a human confirms it at MokManager

Recording the third as an enrolment is a lie an administrator acts on: they turn Secure Boot on in firmware and the machine stops booting.

What this does

Adds sbReport() to secureboot-funcs.sh and calls it from each of the three exits, posting the outcome and the certificate fingerprint the task already computes and prints to service/secureboot.report.php.

The fingerprint is not decoration. An enrolment date alone goes stale in silence — FOG has PKI zones, a multi-server CA and certificates that expire, so "enrolled 2026-03-14" says nothing about whether the machine trusts what the server is serving today, which is the question an administrator actually has. sbCertFingerprint() and FOGConfigurationPage::secureBoot() already produce the identical string, so the comparison is equality and there is no new computation on either side.

sbState() is re-read at report time rather than reusing the value from the top of the task, because the db path changes the state it is reporting: writing the PK is what leaves Setup Mode.

Best-effort by design

This is the half worth reading twice. The enrolment has already happened by the time sbReport runs. A server too old to have the endpoint answers 404; an unreachable one answers nothing; in both cases the machine is enrolled and the task must still complete.

So sbReport never calls handleError, always returns 0, and says on screen what did not happen — in words that name the recording as the failure. "Secure Boot enrolment failed" would send the next person to a firmware screen that is perfectly fine:

 * Note: the enrolment succeeded but could not be recorded on the
   FOG server (HTTP 404 from …).
   Set it by hand on the host's General tab if you need the record.

Tests

New tests/checks/secureboot-enrolment-report.sh, twelve cases, mirroring the sandbox-plus-stubbed-curl mechanism of server-post-reporting.sh. It pins:

  • the body carries mac, result, cert and state, and is a POST — the endpoint reads INPUT_POST only, so a call that lost its data argument would still reach a 200 and look fine;
  • nothing is posted when either the result or the fingerprint is missing, so a half-populated row cannot be created — "enrolled, certificate unknown" is worse than no record, because it cannot be told apart from a real enrolment whose cert was cleared;
  • the staged-MOK exit reports mok and never db — anchored on the whole call line, because a grep for the function name alone passes when the argument has been changed, and the argument is the entire point;
  • every exit reports before completing the task — order is load-bearing, since the endpoint requires the enrolment task to still be in flight;
  • unreachable, 404, empty 200 and an unexpected body all return 0 and say so.

Every assertion was made to go red by reintroducing the defect it exists to catch. Two of them were not gates until that was done, and both looked fine on a read-through:

  • the ordering case passed with a report moved below its own completion, because the previous exit's report satisfied it — it remembered the last report rather than consuming it;
  • the argv case passed with the POST turned into a GET.

sh tests/run-all.sh — 17 passed, 0 failed.

Order

Merge fogproject#1451 first. Until the endpoint exists, sbReport gets a 404 and prints its note; nothing else changes, and no task fails either way.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C2gFRQ3Khhx24FNYMZhW6N

fog.enrollsb has three exits and every one of them ends with the same
argument-free `. /bin/fog.nonimgcomplete`, so from the server all three look
identical: the task completed. They are not remotely the same thing.

  db       the machine was in Setup Mode, `db` was written, it IS enrolled
  trusted  it already trusted this certificate; nothing was enrolled here, and
           nothing observed how the trust got there
  mok      a request was STAGED. The machine is NOT enrolled and will not boot
           with Secure Boot on until a human confirms it at MokManager

Recording the third as an enrolment is a lie an administrator acts on: they
turn Secure Boot on in firmware and the machine stops booting. So the outcome
is now reported by the only party that knows it, to the new
service/secureboot.report.php, along with the certificate fingerprint the task
already computes and prints. FOG stores that against the host as its enrolment
record -- an enrolment date alone says nothing once a certificate has rotated,
and FOG has PKI zones, a multi-server CA and certificates that expire.

Best-effort by design, and that is the half worth reading twice. The enrolment
has already happened by the time sbReport runs: a server too old to have the
endpoint answers 404, an unreachable one answers nothing, and in both cases
the machine is enrolled and the task must still complete. So sbReport never
calls handleError, always returns 0, and says on screen what did not happen --
in words that name the RECORDING as the failure, because "Secure Boot
enrolment failed" sends the next person to a firmware screen that is perfectly
fine.

sbState() is re-read at report time rather than reusing the value from the top
of the task, because the db path CHANGES the state it is reporting: writing
the PK is what leaves Setup Mode.

tests/checks/secureboot-enrolment-report.sh covers it, and every assertion in
it was made to go red by reintroducing the defect it exists to catch. Two of
them were not gates until that was done: the ordering case passed with a
report moved below its own completion, because the previous exit's report
satisfied it, and the argv case passed with the POST turned into a GET.

Server side: FOGProject/fogproject#1451, and
docs/adr/0029 there for the whole design.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant