Remediate actionable fixable vulnerabilities in the Linux CCM, CNM, and
health-probe-proxy images for one input target branch.
Require the caller to provide an input branch that is exactly master or
matches ^release-[0-9]+\.[0-9]+$. Operate only on the current checkout;
callers may run this skill concurrently in separate worktrees for separate
input branches.
Sources of Truth
Read these repository skills before taking any action:
.agents/skills/build-images/SKILL.md
.agents/skills/fix-image-cves/SKILL.md
.agents/skills/sync-go-modules/SKILL.md
Follow those skills as the sources of truth for Makefile image builds and
Trivy-based CVE remediation and for final repository-wide Go module
consistency. Do not duplicate, override, or extend their commands. This skill
supplies orchestration, lifecycle, Git, validation, cleanup, and pull-request
policy only. If a dependency is missing or conflicts with this skill, stop and
report the blocker.
Before checking out the input branch, copy this complete skill directory and
all three dependency skill directories into a unique run-scoped temporary
directory outside the repository. Use that exact tooling snapshot for the
entire run; do not depend on skill files present on the target branch.
Invoke both image helpers and the module-sync helper with their explicit
--repo input pointing at the current worktree. Remove the temporary tooling
snapshot during final cleanup.
Git Lock Discipline
Run every orchestration-owned read-only Git inspection with command-scoped
GIT_OPTIONAL_LOCKS=0. This includes status, diff, log, show, rev-parse,
ls-files, ls-tree, and ref checks. The image-CVE and module-sync helpers enforce
the same rule internally for their read-only Git subprocesses.
Do not export this setting across the workflow or pass it to mutating Git
commands. Fetch, checkout, branch or ref updates, staging, commits, and pushes
must run serially with normal required locking. Before each mutation and after
each long-running helper exits, inspect the current worktree Git directory for
lock files. If an unexpected lock exists, stop and report its path, owner,
size, modification time, and holder check when available. Never delete,
rename, bypass, or work around it as part of this skill.
Preconditions
- Require a clean worktree before changing branches. Preserve all pre-existing
work; never reset, discard, or overwrite it.
- Fail fast if Git, GitHub CLI, Trivy, Docker with Buildx or Podman with native
build support, or a local Go version compatible with the checked-out branch
is unavailable. Before each CVE apply, also require an available local Go
version compatible with the fresh plan's Go directive actions. Do not
install or upgrade host software or enable automatic toolchain downloads.
- Require both
git var GIT_AUTHOR_IDENT and
git var GIT_COMMITTER_IDENT to succeed before any build so checkpoint
commits cannot fail after remediation has started.
- Require
upstream to contain the input branch and verify, before any build,
that the current authenticated account can push to origin and open a pull
request against upstream. Check repository permissions rather than
hard-coding classic-token scope names.
- Check for an existing open CVE-remediation pull request targeting the input
branch. If one exists, stop and report its URL instead of creating a
duplicate.
- If this worktree already has unfinished
fix-image-cves state, stop and
report it instead of deleting evidence from an earlier run.
Branch and Image Identity
Validate that the input branch is exactly master or matches
^release-[0-9]+\.[0-9]+$. Fetch and check out its current tip from upstream,
using only a fast-forward update if a local branch already exists. Never
hard-reset a local branch; stop if it cannot be fast-forwarded safely. Then
create a branch named
cve-fix-<input-branch>-<UTC timestamp>, for example
cve-fix-master-20260721T013000Z or
cve-fix-release-1.36-20260721T013000Z.
Use the build skill with:
- image registry:
local
- image tag:
cve-<short-sha>-<UTC timestamp>-<run-id>
- explicit make inputs:
ARCH=amd64 and OUTPUT_TYPE=docker
- inherited make inputs removed:
OUTPUT_FLAG and BUILDX_EXTRA_FLAGS
Generate <run-id> once as a lowercase UUID without hyphens and retain it for
the complete run. The tag must be unique to the run so concurrent worktrees
cannot overwrite, scan, or delete one another's verification images. Pass
those make inputs through the build skill's --set and --unset options on
every build, including rebuilds and final verification builds. These images
are disposable and must never be pushed.
Select one container runtime for the complete run. Respect an explicit
CONTAINER_CLI; otherwise use the Makefile preference of Podman when available
and Docker otherwise. Resolve and record its absolute path, then pass it through
the build skill as --set CONTAINER_CLI=<path> on every build. Do not build with
one runtime and scan or clean up with another.
After each build, use the selected runtime to resolve and record the canonical
local image reference. Use that exact reference for Trivy scans, rescans, and
cleanup. Podman may normalize local/... to localhost/local/...; do not
assume the Makefile reference is also the canonical runtime reference.
Verification Set
Use this order and identity in every phase:
For every build, allow concurrent builds from other worktrees. Docker builds
share a host-level Buildx builder; Podman uses its native builder. Pass the
build helper's --retry-transient-runtime-errors option on every build. The
build skill owns runtime-specific failure classification, health checks,
bounded delay, exact retry execution, and the two-attempt limit. Do not run an
additional outer retry. If the helper still returns a failure, preserve both
attempts in the run summary and stop.
Baseline Phase
Establish the three-image baseline before mutating source:
- Build all three images from the untouched input-branch source before running
any
fix-image-cves apply command.
- For each baseline image, run
scan and plan with its canonical image
reference, module root, and Dockerfile. Record the complete plan, actionable
findings, unsupported fixable findings, and residual risks outside the
helper state before scanning the next image.
- Treat Go toolchain findings and findings without a
FixedVersion as
residual risks. Treat any OTHER finding with a non-empty FixedVersion as
an unsupported fixable finding and stop without applying changes or opening
a PR, preserving that image's state.
- The helper has one worktree-local state file. When continuing, run its
clean command after recording each successful baseline result so the next
image starts with empty state. If a baseline scan or plan fails, preserve
that image's state and stop.
If all three baseline plans contain zero Go-module actions, zero base-image
actions, and zero unsupported fixable findings, exit successfully without
committing, pushing, or opening a PR. Only residual findings may remain on this
no-change path.
After the complete baseline is recorded, process images sequentially in the
table order:
- Rebuild the image from the current source and resolve its canonical runtime
reference. Run a fresh
scan and plan; do not apply the saved baseline
plan because an earlier image may already have changed a shared module.
- Review every fresh plan. If it contains Go directive actions, select a
locally installed Go version at least as new as the highest target before
apply, and keep
GOTOOLCHAIN=local. Apply Go-module and directive fixes
through fix-image-cves, including compatible pinned Go builder targets
for every affected verification Dockerfile (both CCM and CNM for the root
module). Follow the fix skill's Dockerfile:builder target policy; keep
already-compatible builders unchanged. For a fixable runtime base-image
finding, automatically replace only the digest of the existing registry,
repository, and tag. If runtime base-image remediation would change the
image family or tag, stop for review. Stop and report any other permission, judgment, or
conflict-resolution requirement instead of guessing.
- If the fresh plan contains no Go-module or base-image actions and no
unsupported fixable findings, record its residual risks, run
clean, and
continue to the next image. Skip apply, file verification, remediation
rebuild, and planned-key rescan for this zero-action plan.
- If the fresh plan has actions, run
apply, then file verification. Rebuild
the image and run verify --rescan to prove the planned vulnerability keys
disappeared.
- Before starting a new scan, record the apply state's exact modified-file
list and verification results;
scan replaces prior apply and verify state.
Then run a fresh scan and plan of the rebuilt image to detect newly
introduced actionable or unsupported fixable findings.
- After the fresh plan is reviewed, commit only the recorded modified files as
the checkpoint for that cycle. Do not commit immediately after file
verification. The fresh plan need not be empty for an intermediate cycle.
Never reset or revert an earlier checkpoint, and keep all checkpoint commits
in the final PR.
- If the fresh plan has no remaining actions or unsupported fixable findings,
record residual risks, run
clean, and continue to the next image. If it has
more actions, use that current plan for the next cycle. Allow at most three
apply/verify/fresh-plan cycles per image.
- If verification fails, an unsupported fixable finding appears, or actions
remain after the third cycle, mark the run incomplete. Stop without pushing
or opening a PR and preserve the current helper state, source changes, and
local checkpoint commits for diagnosis.