feat: container image digest pinning in actions-lock.json with update/upgrade integration#25619
feat: container image digest pinning in actions-lock.json with update/upgrade integration#25619
Conversation
- Extend ActionCache with ContainerPins map (stored in actions-lock.json) - Add ContainerPin type with image, digest, and pinned_image fields - Modify collectDockerImages to apply cached digest pins and store images in WorkflowData - Add DockerImages field to WorkflowData for header/manifest tracking - Extend GHAWManifest with containers field (in gh-aw-manifest JSON) - Add Container images used: section to lock file header comments - Create UpdateContainerPins CLI function that resolves digests via Docker - Integrate container pin update into upgrade command (step 3b) - Recompile all lock files with updated manifest and header format Agent-Logs-Url: https://github.com/github/gh-aw/sessions/688c5141-cf5f-4a69-9935-1dad34a50e18 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
…o manifest, add update command integration - Rename ActionCache JSON key from container_pins to containers - Add GHAWManifestContainer type with image/digest/pinned_image fields - Change GHAWManifest.Containers from []string to []GHAWManifestContainer - Track DockerImagePins []GHAWManifestContainer in WorkflowData for manifest - Add UpdateContainerPins to update command (not just upgrade) - Recompile all lock files Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0d5cf327-a467-40fa-8347-f0e797db7dd4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 88fe858:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot merge main, recompile |
…-image-digest-pinning-again # Conflicts: # .github/workflows/smoke-gemini.lock.yml Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/f30c4d46-0535-4d8e-b0c0-338e66445fe9 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 8c6572d. Merged Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
Extends the existing action pinning/locking system to also support Docker image digest pinning and surfaces container usage in generated workflow lock headers and the embedded gh-aw-manifest.
Changes:
- Add container pin storage to
actions-lock.jsonviaActionCachecontainer pin CRUD + (de)serialization. - Collect workflow container images during compilation, emit them in lock header comments, and include structured container info in
gh-aw-manifest. - Integrate
UpdateContainerPins()intogh aw updateandgh aw upgradeto discover images from.lock.ymlfiles and resolve digests via Docker.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/action_cache.go | Adds container pin data model + load/save support in the action cache. |
| pkg/workflow/docker.go | Collects container images at compile-time and applies cached digest pins. |
| pkg/workflow/compiler_types.go | Extends WorkflowData with DockerImages/DockerImagePins for header + manifest output. |
| pkg/workflow/compiler_yaml.go | Embeds containers into gh-aw-manifest and adds a “Container images used” header section. |
| pkg/workflow/safe_update_manifest.go | Extends manifest schema to include container image entries. |
| pkg/workflow/safe_update_manifest_test.go | Updates manifest tests for the new constructor signature. |
| pkg/workflow/action_cache_container_pin_test.go | Adds unit tests for container pin CRUD and JSON round-tripping. |
| pkg/workflow/docker_pin_test.go | Adds unit tests for container pin application/merging and WorkflowData population. |
| pkg/cli/update_container_pins.go | Adds discovery of container images from .lock.yml and digest resolution via Docker CLI. |
| pkg/cli/update_container_pins_test.go | Adds tests for extracting container images from lock files. |
| pkg/cli/update_command.go | Runs container pin updates during gh aw update. |
| pkg/cli/upgrade_command.go | Runs container pin updates during gh aw upgrade before compilation. |
| .github/workflows/ace-editor.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/approach-validator.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/archie.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/architecture-guardian.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/artifacts-summary.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/auto-triage-issues.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/blog-auditor.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/bot-detection.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/brave.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/breaking-change-checker.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/changeset.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/cli-consistency-checker.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/code-simplifier.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/codex-github-remote-mcp-test.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/commit-changes-analyzer.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/contribution-check.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/copilot-cli-deep-research.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/craft.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-assign-issue-to-user.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-choice-test.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-cli-performance.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-community-attribution.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-fact.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-file-diet.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-malicious-code-scan.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-regulatory.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-safe-output-integrator.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-safe-outputs-conformance.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-secrets-analysis.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-security-red-team.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-syntax-error-quality.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-team-evolution-insights.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-team-status.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-testify-uber-super-expert.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/daily-workflow-updater.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/delight.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/dependabot-burner.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/dependabot-go-checker.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/design-decision-gate.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/dev.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/dictation-prompt.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/discussion-task-miner.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/docs-noob-tester.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/draft-pr-cleanup.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/duplicate-code-detector.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/example-permissions-warning.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/firewall.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/functional-pragmatist.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/github-remote-mcp-auth-test.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/go-pattern-detector.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/issue-arborist.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/issue-monster.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/issue-triage-agent.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/layout-spec-maintainer.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/mergefest.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/notion-issue-summary.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/plan.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/pr-triage-agent.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/refiner.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/repo-tree-map.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/research.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/schema-feature-coverage.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/security-compliance.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/semantic-function-refactor.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-agent-all-merged.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-agent-all-none.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-agent-public-approved.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-agent-public-none.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-agent-scoped-approved.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-call-workflow.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-create-cross-repo-pr.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-multi-pr.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-project.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-service-ports.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-temporary-id.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-workflow-call-with-inputs.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/smoke-workflow-call.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/sub-issue-closer.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/terminal-stylist.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/test-dispatcher.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/test-project-url-default.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/test-quality-sentinel.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/test-workflow.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/typist.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/ubuntu-image-analyzer.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/update-astro.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/video-analyzer.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/weekly-editors-health-check.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/weekly-safe-outputs-spec-review.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/workflow-generator.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/workflow-health-manager.lock.yml | Manifest/header regenerated to include container list. |
| .github/workflows/workflow-skill-extractor.lock.yml | Manifest/header regenerated to include container list. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 200/200 changed files
- Comments generated: 3
| result = append(result, []byte(" }")...) | ||
|
|
||
| // Add container_pins section if non-empty | ||
| if len(c.ContainerPins) > 0 { | ||
| pinKeys := make([]string, 0, len(c.ContainerPins)) | ||
| for k := range c.ContainerPins { |
There was a problem hiding this comment.
marshalSorted now supports emitting a non-empty "containers" section, but ActionCache.Save still appears to treat the cache as “empty” based only on Entries. If Entries is empty but ContainerPins is non-empty, Save may skip writing/deleting the file, dropping container pins. Consider updating Save’s emptiness check to keep/write the file when ContainerPins has data (even if Entries is empty).
| for i, img := range images { | ||
| if cache != nil { | ||
| if pin, ok := cache.GetContainerPin(img); ok { | ||
| result[i] = pin.PinnedImage | ||
| pins[i] = GHAWManifestContainer(pin) | ||
| dockerLog.Printf("Pinned container image: %s -> %s", img, pin.PinnedImage) | ||
| continue |
There was a problem hiding this comment.
The conversion GHAWManifestContainer(pin) is not valid unless ContainerPin and GHAWManifestContainer have identical underlying struct types (including identical field tags). These structs currently have different JSON tags (omitempty vs not), so this will not compile. Suggest mapping fields explicitly (Image/Digest/PinnedImage) and also only substituting when pin.PinnedImage is non-empty to avoid emitting an empty image ref if the cache entry is malformed.
pkg/cli/update_container_pins.go
Outdated
| // resolveDigestViaBuildx uses "docker buildx imagetools inspect" to get the content | ||
| // digest without pulling the image layers. | ||
| func resolveDigestViaBuildx(image string) (string, error) { | ||
| // docker buildx imagetools inspect IMAGE --format '{{.Manifest.Digest}}' | ||
| // outputs a single line like: sha256:abc123... | ||
| out, err := exec.Command("docker", "buildx", "imagetools", "inspect", | ||
| image, "--format", "{{.Manifest.Digest}}").Output() | ||
| if err != nil { | ||
| return "", err |
There was a problem hiding this comment.
resolveDigestViaBuildx/resolveDigestViaPull invoke Docker commands without a context/timeout. Since UpdateContainerPins runs as part of update/upgrade flows, a hung Docker daemon/network operation could block the entire CLI indefinitely. Consider using exec.CommandContext with a reasonable timeout (and capturing stderr via CombinedOutput) so failures are bounded and diagnosable.
|
@copilot review comments |
…d, Docker command timeouts Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2d94cf18-69a0-44f6-ab35-057ebb9b9ca4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…se tests for SetContainerPin Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2d94cf18-69a0-44f6-ab35-057ebb9b9ca4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed all three review comments in b2ab7df (and the prior 47274e4):
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
- Add ContainerPin type and Get/Set/Delete methods to ActionCache - Add GHAWManifestContainer type to safe_update_manifest - Update NewGHAWManifest to accept container entries - Update collectDockerImages to apply cached digest pins and populate WorkflowData - Add mergeDockerImages and mergeDockerImagePins helper functions - Add DockerImages and DockerImagePins fields to WorkflowData - Embed container image list in compiled lock file headers - Add UpdateContainerPins CLI function using docker buildx imagetools inspect - Call UpdateContainerPins from update and upgrade commands - Recompile all lock files to include container image sections Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
All MCP container images (
node:lts-alpine,ghcr.io/github/gh-aw-firewall/*,ghcr.io/github/gh-aw-mcpg,ghcr.io/github/github-mcp-server) were pulled by mutable tag with no SHA-256 pinning —node:lts-alpineis additionally floating across LTS generations. This extends the existing action-pin infrastructure to cover Docker images.Storage —
actions-lock.jsonNew
containerssection alongsideentries, keyed by image tag:{ "entries": { ... }, "containers": { "node:lts-alpine": { "image": "node:lts-alpine", "digest": "sha256:abc123...", "pinned_image": "node:lts-alpine@sha256:abc123..." } } }ActionCachegainsGetContainerPin/SetContainerPin/DeleteContainerPin. Loading a legacy file (nocontainers) is fully backward-compatible.Compilation
collectDockerImagesapplies cached pins, substitutingtag@sha256:…for any image with a stored entry.WorkflowData.DockerImagesaccumulates the resolved (possibly pinned) refs so they can be surfaced in the lock file.WorkflowData.DockerImagePinsaccumulates fullGHAWManifestContainerentries (image, digest, pinned_image) for the manifest.# Container images used:comment section.gh-aw-manifestJSON gains a"containers":[…]field with full structured container info including SHA-256 digest when available:Update/Upgrade integration —
pkg/cli/update_container_pins.goUpdateContainerPins()is called from bothgh aw updateandgh aw upgrade(after action pins, before compile):.lock.ymlfiles fordownload_docker_images.shinvocations to discover in-use image tags.docker buildx imagetools inspect(no pull required); falls back todocker pull+docker inspect.actions-lock.json; next compile embeds the@sha256:…suffix.