From 7c48bd375d36d942fdc005712e927e6267e96b8c Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Thu, 12 Nov 2026 19:37:46 -0300 Subject: [PATCH] fix(oci): keep the tag of a tag@digest Feature reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the pinned reference CLI to v0.90.0 and port its one source change (devcontainers/cli#1311): getRef now splits a tag off the resource of a `name:tag@sha256:…` reference, so `resource` no longer ends in `:tag` and `tag` is reported next to `digest`. The digest still selects the version. The ts-oracle getRef goldens gain the two upstream test inputs (a tag with a digest, and a registry port with both), regenerated from v0.90.0 with `task testdata:ts-oracle`; the existing `z:1@sha256:…` case now expects the split. The other goldens are unchanged under v0.90.0. v0.90.0's other fix is to its npm install script, which this CLI does not ship. The recorded divergence on a digest that fails the pattern (TS logs it and keeps the reference, ParseRef refuses it) stays. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/go-cli.yml | 4 +- README.md | 2 +- docs/DIVERGENCES.md | 6 +-- internal/oci/ref.go | 4 ++ internal/oci/ref_test.go | 3 +- internal/oci/testdata/ts-oracle/ref.json | 51 +++++++++++++++++++++++- reference | 2 +- 7 files changed, 63 insertions(+), 9 deletions(-) diff --git a/.github/workflows/go-cli.yml b/.github/workflows/go-cli.yml index a828139..cff21fd 100644 --- a/.github/workflows/go-cli.yml +++ b/.github/workflows/go-cli.yml @@ -166,7 +166,7 @@ jobs: - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 if: always() with: - name: parity-contract-network-v0.89.0 + name: parity-contract-network-v0.90.0 path: artifacts/ if-no-files-found: error - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 @@ -269,7 +269,7 @@ jobs: - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 if: always() && steps.plan.outputs.run == 'true' with: - name: parity-runtime-v0.89.0-shard-${{ matrix.shard }} + name: parity-runtime-v0.90.0-shard-${{ matrix.shard }} path: artifacts/ if-no-files-found: error # daily only: covdata slice for the cross-lane merge (distinct name per shard). diff --git a/README.md b/README.md index 911550e..56d9891 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ GitHub Releases are not supported targets. “Compatible” means compatibility this scope; it does not mean that every platform or historical upstream behavior is implemented. -A pinned official TypeScript CLI (`reference/`, currently v0.89.0) is the behavioral +A pinned official TypeScript CLI (`reference/`, currently v0.90.0) is the behavioral oracle. Roughly 200 cases run commands through both CLIs and compare exit status, normalized output, and relevant container or registry state. See the [parity matrix](docs/parity/parity-matrix.yaml) and diff --git a/docs/DIVERGENCES.md b/docs/DIVERGENCES.md index e7cbeb9..3772fc2 100644 --- a/docs/DIVERGENCES.md +++ b/docs/DIVERGENCES.md @@ -1,7 +1,7 @@ # Divergences, decisions & accepted limitations This CLI is validated for behavioral parity with the reference TypeScript -`@devcontainers/cli` (pinned at **v0.89.0**, see [`parity/`](parity/)). Where it +`@devcontainers/cli` (pinned at **v0.90.0**, see [`parity/`](parity/)). Where it deliberately differs, the difference is recorded here — this is the durable record of *intentional* departures from the oracle, not a backlog. User-facing additions are documented in [`go-only-features.md`](go-only-features.md). @@ -71,9 +71,9 @@ touches a compared surface, reflected in the parity matrix. earlier unconditional build-arg. - **Two upstream fixes newer than the pinned reference are already ported.** A `${localEnv:VAR:default}` or `${containerEnv:VAR:default}` default keeps its colons - (`my.registry.io:5000/img`; upstream #1213), where v0.89.0 keeps the text up to the next + (`my.registry.io:5000/img`; upstream #1213), where v0.90.0 keeps the text up to the next colon. A read-only mount keeps `:ro` in the Compose override (upstream #881), where - v0.89.0's `convertMountToVolume` drops `readonly`. The `testdata/ts-oracle` goldens + v0.90.0's `convertMountToVolume` drops `readonly`. The `testdata/ts-oracle` goldens record both as divergence cases. - **Dockerfile instructions are read with BuildKit's parser**, not with the reference's regular expressions, when resolving the base image and the `USER` of a Dockerfile. diff --git a/internal/oci/ref.go b/internal/oci/ref.go index 2e04c5c..61fe0c8 100644 --- a/internal/oci/ref.go +++ b/internal/oci/ref.go @@ -65,6 +65,10 @@ func ParseRef(input string) (*Ref, error) { if indexOfLastAt != -1 { resource = input[:indexOfLastAt] + if sep := strings.LastIndex(resource, ":"); sep > strings.LastIndex(resource, "/") { + tag = resource[sep+1:] + resource = resource[:sep] + } digestWithAlgo := input[indexOfLastAt+1:] parts := strings.Split(digestWithAlgo, ":") if len(parts) != 2 { diff --git a/internal/oci/ref_test.go b/internal/oci/ref_test.go index 190ef5e..ef66409 100644 --- a/internal/oci/ref_test.go +++ b/internal/oci/ref_test.go @@ -15,7 +15,8 @@ func tsRef(r *Ref) map[string]string { } if r.Digest != "" { out["digest"] = r.Digest - } else { + } + if r.Tag != "" || r.Digest == "" { out["tag"] = r.Tag } return out diff --git a/internal/oci/testdata/ts-oracle/ref.json b/internal/oci/testdata/ts-oracle/ref.json index 8e71e67..6fddeb6 100644 --- a/internal/oci/testdata/ts-oracle/ref.json +++ b/internal/oci/testdata/ts-oracle/ref.json @@ -721,7 +721,18 @@ "args": [ "ghcr.io/x/y/z:1@sha256:1234567890123456789012345678901234567890123456789012345678901234" ], - "result": null + "result": { + "scheme": "https", + "id": "z", + "owner": "x", + "namespace": "x/y", + "registry": "ghcr.io", + "resource": "ghcr.io/x/y/z", + "path": "x/y/z", + "version": "sha256:1234567890123456789012345678901234567890123456789012345678901234", + "tag": "1", + "digest": "sha256:1234567890123456789012345678901234567890123456789012345678901234" + } }, { "name": "ghcr.io devcontainers/templates", @@ -966,6 +977,44 @@ "a/b/c/d" ], "result": "a/b/c/d" + }, + { + "name": "tag and digest", + "fn": "getRef", + "args": [ + "mcr.microsoft.com/devcontainers/go:2.3.1-1.27-bookworm@sha256:adc326255c019241228f9da4a1cb5d6a89abaaa0eb8d926a355b00af7daafd00" + ], + "result": { + "scheme": "https", + "id": "go", + "owner": "devcontainers", + "namespace": "devcontainers", + "registry": "mcr.microsoft.com", + "resource": "mcr.microsoft.com/devcontainers/go", + "path": "devcontainers/go", + "version": "sha256:adc326255c019241228f9da4a1cb5d6a89abaaa0eb8d926a355b00af7daafd00", + "tag": "2.3.1-1.27-bookworm", + "digest": "sha256:adc326255c019241228f9da4a1cb5d6a89abaaa0eb8d926a355b00af7daafd00" + } + }, + { + "name": "registry port, tag and digest", + "fn": "getRef", + "args": [ + "docker.io:8001/devcontainers/templates/docker-from-docker:1.3.4@sha256:4ef08c9c3b708f3c2faecc5a898b39736423dd639f09f2a9f8bf9b0b9252ef0a" + ], + "result": { + "scheme": "https", + "id": "docker-from-docker", + "owner": "devcontainers", + "namespace": "devcontainers/templates", + "registry": "docker.io:8001", + "resource": "docker.io:8001/devcontainers/templates/docker-from-docker", + "path": "devcontainers/templates/docker-from-docker", + "version": "sha256:4ef08c9c3b708f3c2faecc5a898b39736423dd639f09f2a9f8bf9b0b9252ef0a", + "tag": "1.3.4", + "digest": "sha256:4ef08c9c3b708f3c2faecc5a898b39736423dd639f09f2a9f8bf9b0b9252ef0a" + } } ] } diff --git a/reference b/reference index 5dc7533..d807cb2 160000 --- a/reference +++ b/reference @@ -1 +1 @@ -Subproject commit 5dc7533314b5ba7ec3875c30143dfe1aec644870 +Subproject commit d807cb27c195b6bc0e89d893fc20f44a30bf27ee