fix: strip OCI image tag when pushing attestation to registry - #464
Merged
Conversation
bdehamer
marked this pull request as ready for review
July 29, 2026 16:59
bdehamer
marked this pull request as draft
July 29, 2026 16:59
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes registry-push failures when an OCI subject discovered from $GITHUB_ARTIFACTS_LIST includes a :tag, by preserving the tag in the signed attestation subject while stripping it at the @sigstore/oci push boundary.
Changes:
- Add
stripOCITaghelper and use it increateAttestationfor registry credentials lookup, registry URL derivation, artifact attachment, and storage record naming. - Keep OCI tags in
parseArtifactsListoutput (still optionally lowercased) so provenance subjects remain faithful. - Add unit + integration tests and update fixtures; regenerate
dist/.
Show a summary per file
| File | Description |
|---|---|
| src/attest.ts | Strips :tag at registry-push/storage-record boundary while keeping the attestation subject unchanged. |
| src/artifacts.ts | Adds stripOCITag and documents tag preservation behavior for discovered OCI subjects. |
| tests/unit/artifacts.test.ts | Adds unit coverage for tag preservation and stripOCITag behavior. |
| tests/integration/attest.test.ts | Ensures tag is preserved in attestation subjects but stripped for registry push and storage record creation. |
| tests/fixtures/mocks.ts | Adds a tagged OCI subject fixture for integration tests. |
| dist/index.js | Updates bundled output to reflect source changes. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 5/6 changed files
- Comments generated: 2
- Review effort level: Low
An OCI subject discovered from $GITHUB_ARTIFACTS_LIST can carry a :tag in its name (e.g. ghcr.io/owner/app:12345) when the producer captures a tagged reference. The registry-push path passes the subject name to @sigstore/oci's parseImageName, which only accepts a bare "registry/repository" reference and throws "Invalid image name" on any tag. Normalize OCI names by stripping a trailing :tag before dedup and registry push. The entry's digest already pins the exact image, so the tag is redundant. A registry port (e.g. localhost:5000/repo) is preserved by only stripping a colon that appears after the final path separator. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f0a618f-2ff5-464e-9c70-e29acccf2c3d
Preserve any `:tag` on discovered OCI subjects in the attestation subject and strip it only when attaching/pushing the attestation to the registry, where a bare `registry/repository` reference is required. The subject digest already pins the exact image. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f0a618f-2ff5-464e-9c70-e29acccf2c3d
This is an internal push-boundary detail that doesn't need end-user docs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f0a618f-2ff5-464e-9c70-e29acccf2c3d
Guard stripOCITag against digest references (e.g. "…/app@sha256:…"): the ':' inside a digest is not a tag separator, so bail out when an '@' is present to avoid returning a corrupt reference. Add unit coverage for digest and tag+digest forms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f0a618f-2ff5-464e-9c70-e29acccf2c3d
Rename stripOCITag -> bareImageName and strip both tag and digest suffixes so the registry-push boundary always receives a valid bare "registry/repository" reference, covering all four reference forms: foo/bar, foo/bar:tag, foo/bar@sha256:…, foo/bar:tag@sha256:… The previous "@"-guard merely returned digest references unchanged, which @sigstore/oci still rejects. A registry port (colon before the final path separator) is still preserved. Add unit coverage for the digest and port+digest forms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f0a618f-2ff5-464e-9c70-e29acccf2c3d
bdehamer
force-pushed
the
bdehamer/strip-oci-subject-tag
branch
from
July 29, 2026 18:23
babaca7 to
4bf3eb4
Compare
bdehamer
marked this pull request as ready for review
July 29, 2026 18:23
malancas
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a subject is discovered via
$GITHUB_ARTIFACTS_LISTfor an OCI image, thenamemay include a:tag(e.g.ghcr.io/owner/app:v1). Pushing theattestation to the registry via
@sigstore/ocifails on such names becauseparseImageNameonly accepts a bareregistry/repositoryreference:Approach
The image tag is preserved in the attestation subject (it's meaningful
provenance) and stripped only at the registry-push boundary in
attest.ts.The subject digest already pins the exact image, so a bare reference is
sufficient for attaching/pushing the attestation.
parseArtifactsListnow records OCI subjects faithfully (tag preserved;downcaseOCIstill applied for the push flow).stripOCITagis applied increateAttestationforgetRegistryCredentials,attachArtifactToImage,getRegistryURL, and the storage record — so thesigned attestation keeps
…/app:v1while the push targets…/app./is treated as a tag, so a registry port(e.g.
localhost:5000/repo) is preserved.Testing
stripOCITag(tag stripping, port preservation, no-op cases)and tag-preservation in parse output.
registry-push path and storage record receive the stripped name.
dist/regenerated.