Conversation
crane operates directly on the registry for every mutation — each append, mutate, or edit-config call creates a new manifest, leaving the previous one as an untagged image. Over time this accumulated significant registry garbage that GHCR's permission model made impossible to clean up automatically. buildah builds images locally and pushes the finished manifest in a single operation, producing zero intermediate untagged manifests. skopeo handles read-side operations (inspect, copy/retag, export). Split the CI publish job into per-arch and combined stages so the combined image can depend on per-arch images already in the registry. Add --force flag to allow overwriting existing images when needed. Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Documents the progression from ORAS to crane to buildah+skopeo and the specific problems that motivated each migration. Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates CaptainOS OCI artifact publishing/tagging/pulling away from crane to a local-build workflow using buildah (write-side image construction) and skopeo (read-side inspect/copy/export), aiming to eliminate intermediate untagged registry manifests in GHCR and reduce registry garbage.
Changes:
- Replaces crane-based OCI mutation with buildah-built images pushed in a single operation; introduces a skopeo wrapper for inspect/copy/export.
- Updates release tooling/dependency checks and the release container image to include buildah+skopeo.
- Refactors CI publishing into per-arch and combined stages and adds a
--forceflag to overwrite existing images when needed.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/design-decisions/oci-tooling-buildah-skopeo.md | Adds design rationale and history for moving to buildah+skopeo. |
| captain/util.py | Updates native release dependency checks to require buildah+skopeo. |
| captain/skopeo.py | Adds skopeo wrapper for existence checks, digest inspection, retagging, and export/extraction. |
| captain/buildah.py | Adds buildah wrapper for local image construction and manifest list management. |
| captain/oci.py | Reimplements publish/pull/tag flows using buildah+skopeo; adds combined/per-arch publish helpers and force behavior. |
| captain/docker.py | Updates release container runner to support buildah execution (adds privileged + isolation env). |
| captain/crane.py | Removes crane wrapper module. |
| captain/cli.py | Adds --force to release publish CLI and forwards it through docker/native execution paths. |
| Dockerfile.release | Rebuilds release image to include buildah+skopeo and related configuration. |
| .github/workflows/release.yml | Removes crane installation step from release workflow. |
| .github/workflows/ci.yml | Splits publishing into per-arch and combined jobs and removes crane installation steps. |
Comments suppressed due to low confidence (1)
.github/workflows/release.yml:37
- This workflow removed crane installation but doesn't install the new release dependencies (
buildah/skopeo)../build.py release pulland./build.py release tagwill fail in native mode without them. Add an explicit install step (apt) before installing Python deps / running the release commands.
- name: Load shared config
run: cat .github/config.env >> "$GITHUB_ENV"
- name: Install Python dependencies
run: pip install -r requirements.txt
- name: Pull release artifacts (both)
env:
VERSION_EXCLUDE: ${{ github.ref_name }}
run: ./build.py release pull --target both --pull-output artifacts/both
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Remove unused fuse-overlayfs from Dockerfile.release (vfs driver) - Drop tar from release dependency check (no longer used) - Raise error on missing layer blob instead of warn+continue - Replace _safe_tar_extract with safe_extractall (rejects symlinks/devices) - Make checksum writing idempotent (skip write if content unchanged) - Rename --target 'both' to 'combined' across CLI, OCI, CI, and release Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 11 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix _build_platform_image docstring (timestamp applies to all commits) - Remove unused arch param from _publish_single_arch - Skip publish recap when combined image already exists - Fix copy() docstring: refs don't include docker:// prefix - Fix blob lookup order: try verbatim digest first - Forward registry auth env vars into release container - Update README: replace crane references with buildah/skopeo Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.github/workflows/release.yml:50
- This workflow logs into GHCR with
docker/login-action, butbuild.py release pull/tagexecute skopeo in the release container (default RELEASE_MODE=docker). Without forwarding an auth file into that container, pulls/retags against GHCR may fail (especially for private packages). Consider wiringREGISTRY_AUTH_FILEinto the release container or performing an explicitskopeo loginwithin it.
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Load shared config
run: cat .github/config.env >> "$GITHUB_ENV"
- name: Install Python dependencies
run: pip install -r requirements.txt
- name: Pull release artifacts (combined)
env:
VERSION_EXCLUDE: ${{ github.ref_name }}
run: ./build.py release pull --target combined --pull-output artifacts/combined
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${{ github.ref_name }}" \
artifacts/combined/* \
--generate-notes \
--title "${{ github.ref_name }}"
- name: Tag OCI artifacts with version
env:
VERSION_EXCLUDE: ${{ github.ref_name }}
run: ./build.py release tag ${{ github.ref_name }}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8a0c87c to
70781de
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Use a temporary local manifest name to avoid collisions on repeated publishes, and remove local manifests and intermediate images in a finally block after push completes. Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
70781de to
35a9d3f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Merge Queue StatusRule:
This pull request spent 5 minutes 11 seconds in the queue, including 5 minutes 2 seconds running CI. Required conditions to merge
|
Description
crane operates directly on the registry for every mutation — each append, mutate, or edit-config call creates a new manifest, leaving the previous one as an untagged image. Over time this accumulated significant registry garbage that GHCR's permission model made impossible to clean up automatically.
buildah builds images locally and pushes the finished manifest in a single operation, producing zero intermediate untagged manifests. skopeo handles read-side operations (inspect, copy/retag, export).
Split the CI publish job into per-arch and combined stages so the combined image can depend on per-arch images already in the registry. Add --force flag to allow overwriting existing images when needed.
See the design doc for more details.
Fixes: #
How Has This Been Tested?
How are existing users impacted? What migration steps/scripts do we need?
Checklist:
I have: