feat(oci): plan immutable release tags - #10
Merged
Merged
Conversation
Add internal/rel, the puboci StateReader port and planning engine, the oras-go v2 read adapter, and the plan tags command. No workflow change: the github-script planner stays authoritative until the two-phase path lands.
Round-1 review and conformance fixes: default oras retry transport for production reads, transport failures classified retryable, registry credentials held only in the auth closure, CLI Godoc and reference docs corrected, and added coverage for JSON configuration failures.
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.
Implements PR 3 of the
release-cliprogram: the pure release model, the registry read port and planning engine, the oras-go v2 read adapter, and theplan tagscommand. It lands policy ahead of the workflow cutover so it can be reviewed and tested independently.No workflow change. The
actions/github-scriptplanner inpublish-oci-image.yml(OP-10/OP-11/OP-12) stays authoritative until the complete two-phase publication path replaces it, which avoids a mixed native-plan/ORAS-tag protocol.What lands
internal/rel— pure release model:Version(canonical stable triple),Digest,Tag,Scope,Channel/ChannelsFor,TagState,ChannelState,Action,Decision,TagPlan, andPlanTags, with sentinelsErrImmutableTag,ErrChannelCorrupt, andErrStateIncomplete, plus aSecretthat redacts throughString,GoString,MarshalText, andMarshalJSON.internal/stage/puboci—Image/Reference, the consumer-ownedStateReaderport (port 2 of the closed budget of 13), classifiedErrTagAbsent/ErrRetryable/ErrCorruptState,CollectState(fresh reads), andPlanTags.internal/adapter/reg— read-only oras-go v2 (v2.6.2, the version proven by the GHCR parity spike) adapter. It never pushes, tags, or deletes. Credentials are revealed once and held only inside the auth closure. A nil HTTP client selects oras-go's boundedretry.DefaultClient.internal/cli—plan tags [--image] [--version] --digest [--json]with derived defaults fromGITHUB_REPOSITORYandGITHUB_REF_NAME, and the generatedStateReadermock underinternal/adapter/reg/mocks/.docs/reference/release-cli-contract.md,docs/reference/oci-image-contract.md— tag policy, the JSON result, and the direct-CLI single-writer limitation.Behavior preserved
Exact tag: absent creates, same digest accepts, any other digest fails. Channels minor -> major -> latest: absent creates, same digest accepts, otherwise the
org.opencontainers.image.versionannotation is read (only when present and differing, exactly as the workflow does), the release line is enforced for minor and major, and then newer creates, older retains, equal-version-with-different-digest fails.Three deliberate, documented divergences: version components must fit
uint64(the JS used BigInt), a corrupt annotation surfaces a precise error rather than an absent version, and the CLI collects all state before deciding, so it may report a channel failure where the workflow would report the exact-tag conflict first. All three fail closed.Verification
mise exec -- moon run root:checkgreen: format, lint, build, test, protocol stamp, mock freshness.PlanTagsdecision table, including release-line violations, equal-version corruption, and deterministic ordering. Layer 2: engine against the generated mock (including proof that the annotation is not fetched when a channel already matches), and the adapter against an in-process OCI registry overhttptestcovering absent tags, corrupt annotations, 429/503 retryable classification, 401, and transport failures.ghcr.io/meigma/releasepackage (0.1.0issha256:bb696ae3...): candidate0.1.0at that digest planned fouracceptdecisions and zero tags; the same version at another digest failed withErrImmutableTagand exit 1; candidate0.2.0planned create for every tag after reading the0.1.0annotation; candidate0.0.1planned create for exact and minor while retaining0andlatest; derived defaults fromGITHUB_REPOSITORY/GITHUB_REF_NAMEresolved correctly; an unreachable registry reported a retryable transport failure with no URL in the message.Review follow-ups recorded, not fixed here