Skip to content

test(e2e): boot the real image in QEMU as a Root and an Intermediate and run the full product suite #295

Closed

Description

@Bugs5382

Summary

The kind test from #293 proves cert-manager can enrol over ACME, but the node side runs in-process: no kernel, no init, no LUKS, no TPM, no real listeners. Nothing in CI boots the image operators actually install and drives it the way they would.

This adds a second, slower test that boots the real CryptOS image (unsigned UKI, swtpm, OVMF) in QEMU on a GitHub-hosted runner as a Root and an Intermediate, and runs a suite of named steps against them over the real mTLS API with cryptosctl. Each step reports pass, fail or skip (with the reason) in the job summary. Anything that needs outside gear (AD/LDAP, Cisco, Palo Alto, VMware) stays out.

It also measures how much of the codebase the booted run exercises: a coverage-instrumented build of the binaries, used only by this test, with per-package percentages in the summary and an HTML report as an artifact. No threshold yet; the first runs set the baseline.

Acceptance criteria

  • Two VMs boot from the same unsigned image: a Root and an Intermediate. The Root runs its ceremony; the Intermediate's CSR is signed by the Root with ca sign-subordinate and submitted back, and the chain verifies.
  • Leaf issuance with ca issue-leaf from CSRs: ECDSA P-384 and RSA 3072 issue, RSA 2048 is refused.
  • The leaf is served by nginx (pinned by digest) with OCSP stapling; curl --cacert and openssl s_client -verify_return_error succeed and the stapled status is good.
  • Revocation: after ca revoke, OCSP answers revoked, the CRL lists the serial and nginx's stapled status turns revoked after a refresh.
  • Protocol switch the production way: config apply with pki.acme and pki.est enabled shows a pending reboot, the reboot clears it and status shows them running; switching ACME off does the same in reverse.
  • ACME: a kind cluster with cert-manager (the pins from test(e2e): prove cert-manager gets a CryptOS certificate over ACME in a kind cluster #293) gets a Certificate from the booted Intermediate over http-01; the chain verifies to the Root, ca list-issued on the node shows the serial, and a forced renewal gives a new serial that is also listed.
  • EST simpleenroll and simplereenroll with curl and openssl.
  • Re-certify the Intermediate on the same key.
  • Escrow export and import on a software-key node (short passphrase refused), refused on a TPM node.
  • The audit chain verifies after all of the above.
  • Console reset on a throwaway VM, driven over the serial console.
  • Steps the code can't do yet skip with a clear message (SCEP until feat(scep): serve SCEP so network devices can enrol a trustpoint #185 lands, SNTP until feat(init): keep the node clock in sync (NTP client with network.ntp_servers) #249 lands, image upgrade if QEMU can't carry it).
  • Coverage: per-package percentages in the job summary, an HTML report artifact, and the production image never built with -cover.
  • task e2e:image runs it on Linux and skips cleanly elsewhere.
  • A separate workflow runs it nightly, on changes to the image build, init, ACME and config paths, and on manual dispatch. It is not a required check, has a 40-minute timeout (split into jobs if needed), pins its tools with checksums, uses KVM when the runner has it and reports TCG otherwise.

Notes

Related: #293 (the fast in-process kind test, which stays the pull-request check), #284 (config apply for ACME and EST, needed for the protocol switch).

Activity

  1. added this to the v1.0.0 milestone on Sep 30, 2026
  2. self-assigned this
    on Sep 30, 2026
  3. added
    enhancementNew feature (feat). Minor version bump.
    skip-changelogExcluded from release notes (chore/ci/test/style).
    on Sep 30, 2026
  4. added theissue type on Sep 30, 2026
  5. Bugs5382 commented on Sep 30, 2026

    @Bugs5382
    ContributorAuthor

    Found while booting the image and fixed in #296: the revocation listener answered 404 to OCSP GET requests (RFC 6960 appendix A.1, the form nginx staples with), because only the exact path /ocsp was routed. It now routes /ocsp/ and decodes the request from the escaped path, with TestOCSPEndpointGETServesResponse covering it.

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature (feat). Minor version bump.skip-changelogExcluded from release notes (chore/ci/test/style).

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions