Skip to content

Persist OCI manifest content model per image digest - #455

Merged
chruffins merged 15 commits into
mainfrom
hypeship/manifest-layer-model
Sep 2, 2026
Merged

Persist OCI manifest content model per image digest#455
chruffins merged 15 commits into
mainfrom
hypeship/manifest-layer-model

Conversation

@chruffins

@chruffins chruffins commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

summary

This PR persists an OCI manifest content model for each image digest and updates local image tagging to support shared content, restart recovery, and later layer-level cleanup.

persisted manifest model

Ready images store images/content/<digest>/manifest.json containing:

  • manifest digest and media type
  • resolved platform (os/arch[/variant])
  • config digest and ordered rootfs.diff_ids
  • ordered layer descriptors (compressed digest, size, media type) paired with diff IDs

The model is extracted from the existing OCI layout cache during the pull's metadata phase, without additional registry downloads. Writes use the shared atomic JSON helper. blobReferences() exposes the config and layer digests for later cleanup.

Legacy images remain readable in their existing layout. They are promoted lazily when shared content is needed, and missing legacy models remain valid.

image tagging and recovery

  • Pending tag claims are persisted and restored across restarts.
  • Multiple pending tags can claim the same completed digest.
  • Newer requests for a tag are not resurrected by an older build.
  • Digest and tag requests retain credential-conflict checks.
  • Tag and digest deletion keep metadata, symlinks, pending claims, and orphan cleanup consistent.
  • Resource tags remain associated with individual references.

refactoring

The image manager and storage code now split large paths into focused helpers for:

  • digest versus tag deletion
  • interrupted-build recovery
  • pending metadata creation
  • finalization rollback and manifest persistence
  • OCI runtime metadata versus manifest-model extraction
  • filesystem metadata walking versus aggregation
  • pending tag claim and cancellation handling

The main hotspots listAllMetadata, DeleteImage, claimRequestedTags, and cancelPendingTag are no longer high-complexity functions.

validation

  • Targeted manifest-model, metadata-layout, tagging, recovery, deletion, legacy-promotion, and resource-tag tests pass.
  • go test ./lib/images -run '^$' passes.
  • go vet ./lib/images passes.
  • git diff --check passes.
  • The full image test suite remains environment-blocked where integration tests convert filesystems: mkfs.erofs is not installed. This is the same pre-existing environment limitation.

@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 8255d11 to 1f79ed8 Compare August 26, 2026 18:45
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
-->

✱ stlc build

go code · compare

Your SDK build was successful.

generate ✅bootstrap ✅format ✅

116 files generated at cf7a47a (pushed)

go get github.com/kernel/hypeman-go-staging@cf7a47a8fe1d7812e008ec8d55a5496d3b4bd0e6
python code · compare

Your SDK build was successful.

generate ✅bootstrap ✅format ✅

232 files generated at 309c4c8 (pushed)

typescript code · compare

Your SDK build was successful.

generate ✅bootstrap ✅format ✅

138 files generated at fb43b25 (pushed)

Diagnostics: ❗ 0 new / 1 total error, 💡 0 new / 5 total note
LevelCodeMessageTargets
Build metadata
Buildbd_76FzwzCZ-flowery-drop
Timestamp2026-08-31T22:04:44.266Z
stlc8413509
Spec hash1061c067fc80
Config hash659c3687c3f0

This comment is auto-generated by stlc and is kept up to date as you push.
If you push new commits, re-run this workflow to update this comment.
Last updated: 2026-08-31 22:05:15 UTC

@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch 2 times, most recently from 1d3b38c to e6fdc4c Compare August 26, 2026 18:53
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 345e8e0 to 07373a3 Compare August 26, 2026 18:55
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 07373a3 to e8971b4 Compare August 26, 2026 18:58
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from e8971b4 to 4639430 Compare August 26, 2026 19:26
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 4639430 to 273909b Compare August 26, 2026 19:30
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 31c4161 to c6dcc2c Compare August 26, 2026 19:47
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from c6dcc2c to cc7944c Compare August 26, 2026 22:22
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch 2 times, most recently from b42b87c to 50bee89 Compare August 31, 2026 21:35
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch 2 times, most recently from b992e00 to 76c7b91 Compare August 31, 2026 21:56
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 76c7b91 to 5b0a0df Compare August 31, 2026 21:59
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from 5b0a0df to dd879d9 Compare August 31, 2026 23:37
Base automatically changed from hypeship/image-tag-api to main September 1, 2026 14:39
@chruffins
chruffins force-pushed the hypeship/manifest-layer-model branch from b2941b0 to a6e571e Compare September 1, 2026 15:16
@chruffins
chruffins marked this pull request as ready for review September 1, 2026 15:45

@sjmiller609 sjmiller609 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. secondary tag stays stale

starting state

# stable currently resolves to digest A
kernel images create app:stable

# registry updates latest and stable to digest B
docker tag app@sha256:B app:latest
docker tag app@sha256:B app:stable
docker push app:latest
docker push app:stable

# start pulling B through latest
kernel images create app:latest

action

kernel images create app:stable

expected: both tags move to B.
actual: only latest moves; stable remains on A.

2. resource labels are ignored

starting state

kernel images create app:latest --tag team=platform
kernel images wait app:latest

action

kernel images create app:latest --tag team=payments

expected: app:latest reports team=payments.
actual: the reused image retains team=platform.

3. readiness returns too early

starting state

# A is ready
kernel images create app@sha256:A
kernel images tag app@sha256:A app:latest

# start B, then a newer C
kernel images create app@sha256:B --as app:latest
kernel images create app@sha256:C --as app:latest

# C subsequently fails; B remains in progress

action

kernel images wait app:latest

expected: wait for B.
actual: immediately succeeds using old ready image A.

4. eager migration potentially risky

If the migration fails for some reason, it's stuck in image not ready until content/A is manually removed.

Consider a no-op migration instead: leave existing images in the legacy layout, use the shared format only for new images, support reads from both layouts, and add lazy migration only when a future feature requires manifest.json.

@chruffins

Copy link
Copy Markdown
Contributor Author

bugs addressed + found 1 more, re-running CI now

@chruffins
chruffins merged commit ac9e4d3 into main Sep 2, 2026
10 of 11 checks passed
@chruffins
chruffins deleted the hypeship/manifest-layer-model branch September 2, 2026 18:01
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