Skip to content

test(server): prove the armed forge-secret boot path with the real resolver (RIG-3656) - #1155

Merged
trunk-io[bot] merged 4 commits into
compass-server/rig-3655-t4-master-keyfrom
compass-server/rig-3656-armed-boot-test
Sep 12, 2026
Merged

trunk-io[bot] merged 4 commits into
compass-server/rig-3655-t4-master-keyfrom
compass-server/rig-3656-armed-boot-test

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

This PR is part of a stack containing 7 PRs:

  1. main
  2. docs(server): scope user secrets per tenant, user, and agent (RIG-3655) #1110
  3. feat(envelope): AES-256-GCM seam for user-secret values (RIG-3655 T1) #1111
  4. feat(store): scope and encrypt user secrets at rest (RIG-3655 T2) #1118
  5. feat(secrets): add the DB-backed StoreResolver (RIG-3655 T3) #1138
  6. docs(server): require admin for tenant-scoped secret writes (RIG-3655) #1141
  7. feat(server): resolve the at-rest master key at boot (RIG-3655 T4) #1146
  8. "test(server): prove the armed forge-secret boot path with the real resolver (RIG-3656)" (this PR)

The resolver's read path does not shell the CLI: Resolve calls the
secretspec-go SDK, a purego binding that dlopens a libsecretspec cdylib
via SECRETSPEC_FFI_LIB. Only the write-path CLI was staged, so the armed
boot-path test skipped in CI and proved nothing there.

nixpkgs packages only the secretspec crate, whose derivation emits a
single bin output, so the cdylib is built from the upstream workspace
member. The version comes from the pinned nixpkgs package the CLI is
built from, so the CLI, the go.mod SDK pin, and the cdylib cannot drift.

Staged into the Real-Postgres lane only -- it is the sole lane that
compiles a cdylib consumer -- and exported into the dev shell so a local
run matches CI.

Refs RIG-3656

Co-authored-by: Matt Wilkinson matt@rigel.build

rigel-mintaka and others added 2 commits September 12, 2026 11:26
…solver (RIG-3656)

Every other forge pgtest injects a fakeResolver, so the real
SpecResolver -- which fail-closes a configured deployment when a
declared secret is unreadable -- was never exercised at boot.

The test drives buildBoardWebhookWiring with a configured App against
the real resolver over real Postgres. Declarations come from the
production declareServerSecretNames and the dotenv fixture is DERIVED
from the read-back rows, never hand-listed: buildManifest marks every
declaration required, so a hand-listed fixture silently under-provides
the moment a declaration is added.

It asserts the wiring armed component by component rather than only
err == nil, because the not-configured path also returns a nil error, and
asserts the webhook-secret closure returns the fixture value byte for
byte -- that is what proves the value flowed from the provider through
the real resolver instead of the path merely constructing.

Refs RIG-3656

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…eeds (RIG-3656)

The resolver's read path does not shell the CLI: Resolve calls the
secretspec-go SDK, a purego binding that dlopens a libsecretspec cdylib
via SECRETSPEC_FFI_LIB. Only the write-path CLI was staged, so the armed
boot-path test skipped in CI and proved nothing there.

nixpkgs packages only the secretspec crate, whose derivation emits a
single bin output, so the cdylib is built from the upstream workspace
member. The version comes from the pinned nixpkgs package the CLI is
built from, so the CLI, the go.mod SDK pin, and the cdylib cannot drift.

Staged into the Real-Postgres lane only -- it is the sole lane that
compiles a cdylib consumer -- and exported into the dev shell so a local
run matches CI.

Refs RIG-3656

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@linear-code

linear-code Bot commented Sep 12, 2026

Copy link
Copy Markdown

RIG-3656

@rigel-mintaka
rigel-mintaka added this pull request to stack #1112 September 12, 2026 15:27
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-server-rig-3656-arme.compass-eng-docs.pages.dev

Deployed from compass-server/rig-3656-armed-boot-test at 7b0c918.

…t skip (RIG-3656)

The HIGH review finding: the generated PEM was only carried as bytes.
NewAppTokenSource just nil-checks the key -- parsing lives in mint ->
parseRSAPrivateKey, reached only on a first Token call -- and
validateForgeSecret checks the app-key NAME, never its value. Swapping
the fixture for the literal string NOT-A-PEM-AT-ALL left the test
passing, so the comment claiming a parseable PEM mattered was false.

The test now drives Token() against an httptest server, so production
parseRSAPrivateKey runs on the key that came through the real resolver.
appAPIBase always builds an https base, so no Host value reaches a
loopback plain-HTTP server; a rewriting Transport is the hermetic seam,
matching forge's own test idiom. That same mutation now fails with
'parse app private key: no PEM block found'.

Second finding: nothing enforced that the test RAN in CI. It skips when
libsecretspec is absent, and a per-test skip inside a package with other
passing tests still reports ok, so dropping the env line would silently
restore the skipping-in-CI state. The existing ran-rather-than-skipped
guard now also fails on a skip line, deriving the test names from the
skip message so a rename cannot leave it inert. Verified against a real
skip log: it fires; against a pass log it stays quiet.

Refs RIG-3656

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@trunk-io

trunk-io Bot commented Sep 12, 2026

Copy link
Copy Markdown

😎 Stack merged successfully - details.

…uilding it

The pgtest job failed on #1155: the crate has no binary cache, so CI
compiled the cdylib from source and the toolchain step took 17m46s of
the job's 20m budget, leaving the tests two minutes before the job was
cancelled. My box had it cached, so the cost never showed locally.

Upstream publishes the library as a release asset per platform with a
sha256 beside it, so there is nothing to compile. The x86_64 Linux asset
matches its published checksum, and a forced rebuild now costs under a
second. Unlisted hosts throw rather than yield no library.

Refs RIG-3656

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@trunk-io
trunk-io Bot merged commit c4607d2 into main Sep 12, 2026
15 checks passed
@trunk-io
trunk-io Bot deleted the compass-server/rig-3656-armed-boot-test branch September 12, 2026 18:37
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.

2 participants