You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Warn about container images the lockfile can't pin - #193
Closes#168. Addresses #128 as far as static analysis allows.
Part 6 of 7 in the stack; it sits on #196 (nodeselector-opaque-local-action-policy). Review only this PR's commits: compare.
The lockfile pins action commits, not the container images Docker actions pull or build. This PR reports those images as a non-blocking container-image warning, in the terminal and in JSON. It reads only files the CLI already fetches and never pulls an image. valid and exit codes don't change.
Changes
Classifier (internal/dockerimage): any @sha256: reference is pinned, ${{ }} expressions are skipped, and a tag, an untagged image or a Dockerfile build warns. The remediation depends on who controls the image.
Repository images: docker:// steps, job container: and services: images, and the repository's own $/… Docker actions. These are also checked by --verify-local.
Remote actions: a Docker action's runs.image, docker:// steps in remote composites (including transitive ones), and Dockerfile-only actions, using the existing action-file lookup. required_by names the action.
Dedupe: each image is one finding per workflow, listing every job and step that uses it.
Docs: a README coverage table, and the new category recorded in RELEASING. This also restores two Dependabot notes in RELEASING (schema support and the major-release classification).
Tests: run_test.go (TestRemoteContainerImageWarnings, TestContainerImagesNamedInRepository), discovery_test.go, and the Docker scenarios in test/scenarios/catalog.yml.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
In-repository Docker actions silently bypass the new image warnings, leaving a required coverage gap.
No open issues 🎉
What changed in this PR
Adds static, non-blocking container-image warnings for images outside action-lockfile coverage. The supplied diff also includes the underlying release stack.
Changes:
Classify images and collect references from workflows and remote actions.
Report warnings in terminal, JSON, and offline verification without changing validity or exit codes.
Add regression coverage and document coverage limitations.
Review findings:
Moderate, 2 votes:internal/workflowfile/workflowfile.go:388 skips runs.image in in-repository $/… Docker actions, including offline checks. Collect those images, add coverage, and avoid empty Dockerfile built by attribution.
Moderate, 2 votes — optional:test/scenarios/catalog.yml:489 and three related scenarios duplicate command tests. Retain scenarios proving distinct real-binary behavior and explain that distinction, or remove the duplicates.
File
Description
test/scenarios/catalog.go
Updates fixture documentation.
test/integration/harness.rb
Updates example repository text.
RELEASING.md
Records release and compatibility considerations.
internal/workflowfile/source_scan_test.go
Tests source-backed action traversal.
internal/workflowfile/rewrite.go
Excludes reusable calls; removes local migration.
internal/workflowfile/reusable_test.go
Tests reusable-workflow separation.
internal/workflowfile/remoteref.go
Detects malformed remote references.
internal/workflowfile/remoteref_test.go
Tests malformed-reference handling.
internal/tag/testing.go
Disables default cooldown in tests.
internal/tag/tags.go
Caches release metadata.
internal/tag/adoption.go
Enforces cooldown for adopted commits.
internal/tag/adoption_test.go
Tests cooldown boundaries and failures.
internal/resolve/warnings_test.go
Tests image discovery and deduplication.
internal/resolve/reverse_lookup.go
Filters unacceptable provenance references.
internal/resolve/reverse_lookup_test.go
Updates tag-lookup fixtures.
internal/resolve/resolver.go
Separates locked-manifest caching.
internal/resolve/resolver_test.go
Tests traversal and local-action notices.
internal/resolve/discovery_test.go
Tests malformed nested references.
internal/resolve/ancestry.go
Preserves underlying ancestry-check errors.
internal/repospec/repospec.go
Parses remote repository targets.
internal/pipeline/verify_local.go
Adds offline image and reusable-workflow findings.
internal/pipeline/verify_local_test.go
Tests non-blocking offline warnings.
internal/pipeline/run.go
Integrates sources, parity, and completeness checks.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Image deduplication and case-insensitive action detection need fixes; duplicated test scenarios also remain unresolved.
No open issues 🎉
2 previously missed issues
In code that hasn't changed since last review
Normalize image identity across workflow findings
cmd/gh-actions-lock/format/terminal.go:369
Cross-workflow grouping also treats equivalent image spellings as different images: if a.yml uses docker://node:20 and b.yml has container: node:20, their details differ and the terminal prints two warning headers instead of one with both workflow locations. Use a normalized image identity for imageMap and imageOrder, rendering the original finding detail separately.
Merge findings with equivalent docker image spellings
internal/pipeline/diagnose.go:375
[P2] A workflow using both container: node:20 and uses: docker://node:20 produces two container-image findings because Detail() preserves the docker:// prefix. The terminal consequently prints the same image twice rather than merging its locations. Normalize the optional prefix when comparing findings, preserving the pulling-action attribution, and add a mixed job/step regression case.
The lockfile pins an action's commit, not the image a Docker action pulls
or builds. One classifier decides for every source: any @sha256: digest
is pinned (digests are not validated), a ${{ }} expression or an empty
docker:// can't be judged statically and is skipped, and a tag, an
untagged image or a Dockerfile build is mutable. Warnings name the image
as the registry does, so docker://node:20 and node:20 read as one, and
the remediation depends on who controls the reference.
Refs #168, #128
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Classify the images a workflow and its in-repo $/ actions name:
docker:// steps, job containers and services in string or image: form,
and a $/ Docker action's runs.image. Each mutable image is one
non-blocking container-image finding per workflow, listing every job and
step that uses it, in the terminal and in JSON; valid and exit codes are
unchanged. They need no network, so --verify-local reports them too.
runs.using is matched case-insensitively, as the runner does.
Refs #168
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Read the images a remote action runs from the manifests discovery
already fetches: a Docker action's runs.image, a composite's docker://
steps including transitive ones, and a Dockerfile-only action, which the
existing action-file probe already reports. Images are collected per
graph node beside local-action notices and become container-image
findings naming the action and sub-action path; required_by keeps the
owner/repo@ref dependency key. No API request is added.
Refs #168, #128
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A remote composite can write and run a ./ action at run time, as
pypa/gh-action-pypi-publish does to run its container. The CLI can't see
that image, so the local-action notice now says so.
Refs #128
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise the real binary against tag-pinned, digest-pinned and Dockerfile
Docker actions, a remote composite's docker:// step, and job containers
and services beside an own $/ Docker action. Each scenario's stubbed
action.yml is declared in the catalog as stub_manifest, so it ports to
any runner, and its description states the real-binary delta over the
Go command tests.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
State that the lockfile pins action commits, not container images, and
list what is and is not scanned, including called reusable workflows in
other repositories, ./ actions, expressions and Dockerfile FROM lines.
Record the additive container-image category for Dependabot review.
Closes the docs request in #168.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Dependabot accepts lockfile schemas v0.0.2 and v0.0.3, and the
recorded-ref validation candidate needs a major release classification
and Dependabot coordination. Both notes were corrected on the earlier
integration branch (0199a06) and are carried here unchanged; no schema
or version decision is made.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
reusable workflows and in `./…` actions are not scanned. The category is
additive: `valid`, exit codes and existing findings are unchanged, and
Dependabot only acts on `error` findings.
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
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.
Closes #168. Addresses #128 as far as static analysis allows.
Part 6 of 7 in the stack; it sits on #196 (
nodeselector-opaque-local-action-policy). Review only this PR's commits: compare.The lockfile pins action commits, not the container images Docker actions pull or build. This PR reports those images as a non-blocking
container-imagewarning, in the terminal and in JSON. It reads only files the CLI already fetches and never pulls an image.validand exit codes don't change.Changes
internal/dockerimage): any@sha256:reference is pinned,${{ }}expressions are skipped, and a tag, an untagged image or a Dockerfile build warns. The remediation depends on who controls the image.docker://steps, jobcontainer:andservices:images, and the repository's own$/…Docker actions. These are also checked by--verify-local.runs.image,docker://steps in remote composites (including transitive ones), and Dockerfile-only actions, using the existing action-file lookup.required_bynames the action../action's container images aren't covered either.Reading order
internal/dockerimage/image.gointernal/workflowfile/workflowfile.go(containerImages,$/Docker actions)internal/resolve/discovery.goandgraph.go(images collected beside local-action notices)internal/pipeline/diagnose.go(appendContainerImageFinding)cmd/gh-actions-lock/format/terminal.gorun_test.go(TestRemoteContainerImageWarnings,TestContainerImagesNamedInRepository),discovery_test.go, and the Docker scenarios intest/scenarios/catalog.yml.