Add local image tagging on shared content storage - #453
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ab2c694. Configure here.
-->
✱ stlc build✅ go code · compare
✅ python code · compare
✅ typescript code · compare
Diagnostics: ❗ 0 new / 1 total error, 💡 0 new / 5 total note
Build metadata
This comment is auto-generated by stlc and is kept up to date as you push. |
ab2c694 to
d8b8cc3
Compare
0ff7892 to
d537750
Compare
d537750 to
32b6564
Compare
32b6564 to
b7a0db5
Compare
POST /images/{name}/tag creates or updates a repository tag pointing at
an existing ready image without pulling or reconverting it. Sources may
be a tag or digest; targets must carry a tag. Cross-repository targets
promote the digest into shared content first so every alias resolves to
one rootfs copy, and deletion keeps content alive while any repository
tag references it.
The tag symlink is staged and renamed atomically, so retagging an
existing name never leaves a dangling reference.
Ported from the earlier tag draft: verify the generated tag route decodes URL-encoded source names, and keep the builds test mock satisfying the extended Manager interface.
79a0244 to
4e09e59
Compare
Move the target tag generation bump to after the tag symlink is created so a failed TagImage no longer invalidates pending pulls' claims on the target tag. Use toImageFor for the tag response and GetImage. Extract the tag feature from manager.go into tag.go and share reference resolution between GetImage and readyTagImage via resolveRefMetadata. Fix the digest-source test's dead assertion and add no-side-effect and legacy-layout coverage.
Replace the error-code switch helper with full-response equality and collapse repeated tag-call assertion blocks into a shared helper.
sjmiller609
left a comment
There was a problem hiding this comment.
changes requested
-
lib/images/tag.go:37-40— replacing a tag does not garbage-collect its previous digest or refresh disk usage. example:app:stable → sha256:oldapp:latest → sha256:newsha256:oldhas no other tagshypeman tag app:latest app:stablechangesstabletosha256:new- nothing references
sha256:old, but its rootfs remains on disk indefinitely
-
openapi.yaml:2671-2701— the authenticated endpoint omits a401response, unlikePOST /images. add it so the contract and generated SDK response types cover authentication failures consistently.
- Log replaced-content cleanup failures instead of failing the call after the tag is live, and document the collection in TagImage's doc comment - Wrap the existing-target resolve error for consistent 500 context - Clarify the digest-target rejection message - Explain why TagImage bumps tag generation after install, unlike updateExistingReference - Skip restaging tag symlinks that already point at shared content during legacy promotion - Extract shared image-seeding test helper into lib/images/testutil

summary
This PR adds server-side support for
hypeman tag.Adds
POST /images/{name}/tag: create or update a local tag pointing at an image already present locally, without pulling or reconverting. Stacked on the content-addressed storage groundwork.lib/oapi/oapi.goviamake oapi-generate(pinned oapi-codegen), added the route scope, and registered the endpoint instainless.yamlfor SDK generation.flows
The existing image-creation path resolves a registry reference, then reuses a local image or queues a pull and conversion:
ImportLocalImageuses the same reuse-or-queue path with a digest supplied by the local OCI cache. Existing lookups resolve a tag symlink or digest, then read metadata; deletion removes references and garbage-collects unreferenced content.The new tag path operates only on ready local content:
It does not contact a registry, pull layers, or reconvert the rootfs. Same-repository tagging only installs the new reference; cross-repository tagging first makes the shared content available.
why
Separates mutable tag references from immutable digest content so many similar images (e.g. app deployments) can share storage and be retagged cheaply — the Docker-style tag-then-push flow.
validation
go test ./lib/images ./lib/scopes ./lib/builds ./cmd/api -count=1(includes new unit tests: same-repo tag, digest source, cross-repo promotion + GC, not-ready/not-found/digest-target rejection, atomic tag replacement, handler error mapping, route URL decoding)go vet ./...clean