Problem
The --key / --public-key path shipped for skills (#6447, #6478) and plugins (#6524, #6525, #6528) with unit tests only, by agreement on #6442 — the push side did not exist on plugins until the last PR, and cosign is not on the E2E runner. Every test of the path drives the mocked verifier.Verifier; nothing has ever exercised the real signer → registry → verifier chain for a key-pair signature end to end.
That leaves a specific class of bug invisible: a mismatch between what signer.SignOCI writes for a key-pair signature (simple-signing payload, .sig manifest layout, annotations) and what verifier.VerifyOCIWithKey / VerifyBundleOfflineWithKey expect to read back. The mocks agree with each other by construction. bundleSignsPayload (the anti-transplant check) and the "payload recovered from the stored bundle, not rebuilt from a reference" fix in #6525 are exactly the kind of logic that only a real round trip validates.
Proposed scope
Add one Ginkgo spec per surface to test/e2e/ (the plugins side can extend cli_plugins_lock_test.go, which already has the registry + project harness):
cosign generate-key-pair into a temp dir (or check in a fixed test key pair; a checked-in key removes the cosign binary dependency and is fine for a test that asserts behaviour, not secrecy).
thv skill build / thv ai-plugin build, then push --key cosign.key to the local registry with COSIGN_PASSWORD set on the thv serve process.
install --scope project --public-key cosign.pub; assert the lock entry has publicKey and no signerIdentity, and info renders "cosign key pair".
install again with no flag → uses the pinned key; install with a different --public-key → 403 conflict.
sync --check → AlreadyCurrent; tamper with the on-disk tree → drift → sync repairs via the pinned key.
upgrade after pushing a new version signed with the same key → upgraded; after pushing one signed with a different key → failed [signature-invalid] with the reinstall remedy; after pushing keyless → signer-change-blocked.
install --allow-unsigned on the key-signed artifact with no key → 403 naming --public-key, not a recorded unsigned exception.
Also assert the key-signing capability from #6560: a push --key from a client without the discovery capability is refused.
Related
Problem
The
--key/--public-keypath shipped for skills (#6447, #6478) and plugins (#6524, #6525, #6528) with unit tests only, by agreement on #6442 — the push side did not exist on plugins until the last PR, andcosignis not on the E2E runner. Every test of the path drives the mockedverifier.Verifier; nothing has ever exercised the realsigner→ registry →verifierchain for a key-pair signature end to end.That leaves a specific class of bug invisible: a mismatch between what
signer.SignOCIwrites for a key-pair signature (simple-signing payload,.sigmanifest layout, annotations) and whatverifier.VerifyOCIWithKey/VerifyBundleOfflineWithKeyexpect to read back. The mocks agree with each other by construction.bundleSignsPayload(the anti-transplant check) and the "payload recovered from the stored bundle, not rebuilt from a reference" fix in #6525 are exactly the kind of logic that only a real round trip validates.Proposed scope
Add one Ginkgo spec per surface to
test/e2e/(the plugins side can extendcli_plugins_lock_test.go, which already has the registry + project harness):cosign generate-key-pairinto a temp dir (or check in a fixed test key pair; a checked-in key removes thecosignbinary dependency and is fine for a test that asserts behaviour, not secrecy).thv skill build/thv ai-plugin build, thenpush --key cosign.keyto the local registry withCOSIGN_PASSWORDset on thethv serveprocess.install --scope project --public-key cosign.pub; assert the lock entry haspublicKeyand nosignerIdentity, andinforenders "cosign key pair".installagain with no flag → uses the pinned key;installwith a different--public-key→ 403 conflict.sync --check→AlreadyCurrent; tamper with the on-disk tree → drift →syncrepairs via the pinned key.upgradeafter pushing a new version signed with the same key → upgraded; after pushing one signed with a different key →failed [signature-invalid]with the reinstall remedy; after pushing keyless →signer-change-blocked.install --allow-unsignedon the key-signed artifact with no key → 403 naming--public-key, not a recorded unsigned exception.Also assert the key-signing capability from #6560: a
push --keyfrom a client without the discovery capability is refused.Related
--keypush signing has no install-time verification path (plugins) #6442test/e2e/cli_plugins_lock_test.go(existing harness)