Skip to content

feat(security): add the dormant image-signature enforcement probe - #3732

Merged
devantler merged 13 commits into
mainfrom
claude/probe-image-signature-enforcement-3653
Sep 13, 2026
Merged

feat(security): add the dormant image-signature enforcement probe#3732
devantler merged 13 commits into
mainfrom
claude/probe-image-signature-enforcement-3653

Conversation

@devantler

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Motivation

We assert that this cluster refuses unsigned container images. We have never actually seen it
happen. The existing check proves the machinery is running, which is not the same thing — every
first-party image ever pulled here has passed, so a refusal has never been observed. That makes
our supply-chain enforcement claim an inference rather than a fact.

Getting the observation needs write access to a production node, which the agent does not have. But
building the thing that obtains it does not, and that is what was missing — so the work sat behind
a "wait for a human" label while the shippable half went unwritten.

Changes

Adds the probe, switched off. Whoever holds production access can now get the answer by running it,
instead of designing the experiment first.

It is careful about the ways this specific test can lie to you: an image already on the node is
never re-pulled, so it would report a cheerful success having verified nothing; a broken verifier
that refuses everything looks identical to one working correctly; and an image matching no rule is
supposed to be allowed through, so treating that as a failure would raise an alarm on a healthy
cluster. It reports three outcomes rather than two — pass, fail, and "could not tell" — because
collapsing the third into either of the others gives you a false alarm or a false all-clear.

Dormant twice over: nothing triggers it on its own, and an operator must type a confirmation phrase.
It lives in its own workflow so that dispatching the existing read-only checks can never
accidentally write to a node.

Turning on the daily cadence is deliberately not part of this — that is #3336, and it should only
happen once the refusal has actually been observed.

Fixes #3653
Part of #3336

🤖 Generated with Claude Code

`validate-image-verifier-liveness.sh` establishes that Talos' own image
verification is LIVE on every node. That is necessary for enforcement and not
sufficient: every first-party image ever pulled here has PASSED, so a FAILING
verification decision has never been observed to block a pull. #3101's central
claim — that signature verification actually enforces rather than merely being
configured — therefore rests on an inference.

Obtaining the missing observation needs production write access, which
unattended lanes do not hold, so #3336 classes it as an `authority` blocker.
But authoring the probe path is ordinary engineering, and that half is what
this adds, so obtaining the observation is reduced to running it.

Design points that are load-bearing, not incidental:

* It pulls through `talosctl image pull`, which talks to the node's containerd
  directly. A Pod would reach containerd via the Kubernetes API, where Kyverno
  admission also sits, and an admission rejection and a node-side signature
  refusal are indistinguishable from the outside. Using the node layer makes
  admission structurally incapable of producing the result.
* Both refs are asserted ABSENT from the node's content store first.
  Verification happens at pull, so a cached image is never re-pulled and a
  probe that skipped this could report a successful "pull" that verified
  nothing — most confidently for the positive control, the ref most likely to
  be cached already.
* It requires a signed positive control. A verifier refusing EVERYTHING
  produces the same negative result as one working correctly, so without it a
  refusal is not attributable to the signature.
* A refusal must read as a verification failure. An unknown tag or an auth
  error also fails a pull, and counting those would manufacture a PASS from a
  typo.
* An unsigned ref matching NO rule is allowed through by design, so that case
  is INCONCLUSIVE rather than the headline FAIL — otherwise the probe's alarm
  would fire on a healthy cluster.

Three verdicts are kept distinct: PASS (0), FAIL (1, enforcement is not
refusing) and INCONCLUSIVE (3, no statement made). Collapsing INCONCLUSIVE
into either neighbour yields a false all-clear or a false alarm, and the 20
test cases pin all three.

Dormant twice over: no schedule and no pull_request trigger, plus an exact
confirmation phrase the operator must type. Restoring the daily cadence stays
#3336's activation step. The probe lives in its own workflow because the
liveness workflow is read-only against prod while this one writes, and
`workflow_dispatch` runs every job in a workflow.

Its test fakes talosctl from fixtures, needs no cluster and no secrets, and
runs in the required `validate` job.

Fixes #3653
Part of #3336

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…means

Both from the pre-submission self-review.

A node address or image ref beginning with `-` is parsed by talosctl as a FLAG
rather than as the operand it was meant to be (`talosctl image pull
--bogus-flag` answers "unknown flag"). This crosses no privilege boundary —
these are CLI arguments, so whoever sets them can already run talosctl
directly — but it turns a typo into a confusing tool error instead of a clear
one, and on the `workflow_dispatch` path the value arrives from a form field
where a stray leading dash is easy to introduce. Now rejected explicitly, for
the node as well as both refs, and pinned by a case that was verified to fail
when the guard is neutralised.

Also records the one limitation that bounds what a PASS means: the refusal
reason is produced by the node and partly originates from the registry serving
the ref, so it is the single place where text the probe does not control
decides a verdict. The positive control keeps that from being a plausible
false PASS on its own, but a PASS is evidence about a cooperating registry
rather than proof against a hostile one. Better stated than left implicit.

Part of #3653

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

CI is green at af8542ce (23 passing, 6 skipped, zero failures). Requesting review.

Worth a reviewer's attention, since the interesting parts are about what the probe refuses to
conclude rather than what it does:

  • scripts/probe-image-signature-enforcement.sh distinguishes three verdicts — PASS (0), FAIL (1,
    enforcement is not refusing) and INCONCLUSIVE (3, no statement made). The cases most worth
    checking are the ones that must NOT reach PASS or FAIL: a ref already cached on the node
    (verification happens at pull, so a cached ref verifies nothing), a refusal whose reason does not
    read as a verification failure, a failed signed positive control, and an unsigned ref matching no
    rule (allowed by design, so FAIL there would fire the alarm on a healthy cluster).
  • The rules are read from live node state as one resource per rule carrying .spec.imagePattern,
    filtered to phase: running and owned by security.ImageVerificationConfigController.
  • Cleanup removes only refs the probe itself pulled, and the pulled-ref recording lives in the
    callers deliberately — inside the $(...) capture it would be discarded with the subshell.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Changed files ==='
git diff --name-status HEAD^ HEAD

printf '%s\n' '=== Diff ==='
git diff --find-renames --find-copies --unified=80 HEAD^ HEAD -- \
  'scripts/probe-image-signature-enforcement.sh' \
  '.github/workflows/*' \
  'scripts/*test*' \
  'tests/*' || true

printf '%s\n' '=== Candidate files ==='
fd -a -t f . scripts .github 2>/dev/null | sort | rg 'probe-image-signature-enforcement|image-signature|workflow|test' || true

printf '%s\n' '=== Shell script outline / syntax structure ==='
if [ -f scripts/probe-image-signature-enforcement.sh ]; then
  ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true
  nl -ba scripts/probe-image-signature-enforcement.sh
fi

printf '%s\n' '=== Relevant workflow files ==='
for f in $(fd -a -t f . .github/workflows 2>/dev/null | sort); do
  if rg -q 'probe-image-signature-enforcement|workflow_dispatch|signature' "$f"; then
    echo "--- $f"
    nl -ba "$f"
  fi
done

printf '%s\n' '=== Related test and helper references ==='
rg -n -C 5 --glob '*.sh' --glob '*.yml' --glob '*.yaml' --glob '*.bats' \
  'probe-image-signature-enforcement|ImageVerificationConfigController|imagePattern|INCONCLUSIVE|pulled' \
  scripts .github 2>/dev/null || true

Length of output: 165928


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Exact changed-file list ==='
git diff --name-status HEAD^ HEAD

printf '%s\n' '=== New probe implementation ==='
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,430p'

printf '%s\n' '=== Probe behavioral tests ==='
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,450p'

printf '%s\n' '=== CI wiring near probe ==='
nl -ba .github/workflows/ci.yaml | sed -n '285,340p;1090,1140p'

printf '%s\n' '=== Existing Talos image commands and image-list parsing ==='
rg -n -C 8 --glob '*.sh' \
  '(talosctl|TALOSCTL).*(image (list|pull|remove)|get imageverificationrules)|image (list|pull|remove)' \
  scripts .github 2>/dev/null || true

printf '%s\n' '=== Repository verification-rule declaration ==='
rule_file=$(fd -a -t f 'verify-first-party-images.yaml' talos 2>/dev/null | head -n1 || true)
if [ -n "${rule_file}" ]; then
  echo "--- ${rule_file}"
  nl -ba "${rule_file}"
fi

printf '%s\n' '=== ShellCheck availability and static check ==='
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s bash scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
else
  echo 'shellcheck unavailable'
fi

Length of output: 86342


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Current PR delta ==='
git diff --unified=25 HEAD^ HEAD -- scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh

printf '%s\n' '=== Probe-related commit history available locally ==='
git log --oneline -12 -- scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh

printf '%s\n' '=== Tests for signed-image rule matching ==='
rg -n -C 4 --glob '*.sh' \
  'signed.*match|match.*signed|signed_image.*pattern|signed ref.*rule|positive control.*match' \
  scripts scripts/tests

printf '%s\n' '=== Talos ImageVerificationConfig reference semantics ==='
rg -n -C 5 --glob '*.md' --glob '*.yaml' --glob '*.yml' \
  'ImageVerificationConfig|imagePattern|first match|image: ghcr.io' \
  README.md docs talos k8s 2>/dev/null | head -500

Length of output: 59112


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata and base ref ==='
gh pr view 3732 --repo devantler-tech/platform --json number,baseRefName,headRefName,commits,files --jq '{number, baseRefName, headRefName, commits: [.commits[] | {oid,messageHeadline}], files: [.files[] | .path]}'

printf '%s\n' '=== Local refs ==='
git branch -a --no-color
printf '%s\n' '=== Merge base against main ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s head=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD
printf '%s\n' '=== Complete PR diff: probe files ==='
git diff --unified=30 "$base" HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== GitHub PR file patches ==='
gh api "repos/devantler-tech/platform/pulls/3732/files?per_page=100" \
  --jq '.[] | select(.filename == "scripts/probe-image-signature-enforcement.sh" or .filename == "scripts/tests/test-probe-image-signature-enforcement.sh" or .filename == ".github/workflows/probe-image-signature-enforcement.yaml" or .filename == ".github/workflows/ci.yaml") | "FILE: \(.filename)\n\(.patch // "<patch omitted>")\n"'

Length of output: 99182


@devantler Review complete. I found one blocking issue.

  • Line 373 in scripts/probe-image-signature-enforcement.sh: Validate that signed_image matches a live, running verification rule before pulling it. The script validates this only for unsigned_image. An unmatched signed_image is allowed by design and can pull successfully without any signature verification. In that case, the positive control does not exclude a verifier that rejects every rule-matching image. The probe can then return PASS from an unsigned verification-like refusal plus an unrelated successful pull.

    Reuse the rule-matching preflight for signed_image. Return INCONCLUSIVE if it matches no rule. Add a test where an unmatched signed ref succeeds but the probe returns exit status 3 without pulling either ref.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 7f514a15-a269-427d-bab3-457506df3f79

📥 Commits

Reviewing files that changed from the base of the PR and between 491d5ef and d10d481.

📒 Files selected for processing (4)
  • .github/workflows/ci.yaml
  • .github/workflows/probe-image-signature-enforcement.yaml
  • scripts/probe-image-signature-enforcement.sh
  • scripts/tests/test-probe-image-signature-enforcement.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

… rule

CodeRabbit's review finding, and it breaks the probe's central argument.

The rule-match preflight was applied only to the unsigned ref. For that ref the
reason is obvious — an unmatched image is allowed through by design, so refusing
it is not what the probe observes. The signed ref needed the same gate for a
subtler reason: an unmatched signed ref pulls successfully WITHOUT ANY
VERIFICATION HAVING HAPPENED, so its success says nothing about the verifier and
stops excluding the one failure mode the positive control exists for — a
verifier that refuses every rule-MATCHING image.

The probe would then pair a verification-shaped refusal of the unsigned ref with
an unrelated successful pull of an unverified signed ref and report PASS: a false
all-clear on exactly the broken state it was built to detect.

Both refs are now matched against the running rules before either is pulled, and
an unmatched signed control is INCONCLUSIVE. Demonstrated rather than asserted:
with the new gate neutralised the probe returns exit 0 (PASS) on an unmatched
signed control, and the added case catches it (expected 3, got 0). It also
asserts neither ref is pulled in that situation.

The matcher is extracted into `match_rule` so both refs use one implementation,
and the matched pattern for both is now reported, which makes the log evidence
say which rules the verdict rests on.

Part of #3653

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Resolution — CodeRabbit's blocking finding is VALID and fixed in 27efbd36

The finding (comment 5645989571): the rule-match preflight was applied only to
unsigned_image, so an unmatched signed_image could pull successfully without being verified,
leaving the positive control unable to exclude a verifier that refuses every rule-matching image —
and the probe would then report PASS.

Confirmed, and it breaks the probe's central argument. The whole reason the positive control
exists is to distinguish "correctly refusing an unsigned image" from "refusing everything". An
unmatched signed ref never reaches the verifier at all, so its success carries no information about
the verifier, and the refusal of the unsigned ref stops being attributable to the signature.

Demonstrated rather than asserted. I neutralised the new gate and re-ran the suite: the probe
returns exit 0 (PASS) on an unmatched signed control — the exact false all-clear described —
and the added case catches it (expected 3, got 0). Restored, and the suite is green at 22 cases.

The fix. The matcher is extracted into match_rule so both refs share one implementation, both
are matched against the node's running rules before either is pulled, and an unmatched signed
control is INCONCLUSIVE with neither ref pulled (also asserted). The matched pattern for both refs
is now printed, so the log says which rules the verdict rests on.

One note on this round, recorded because it matters for how the result is read: that same
comment body ends with ⚠️ Action not completed / Review rate limited. The review nonetheless
produced a real, correct finding, so I treated it as findings-bearing rather than as a refusal —
a refusal marker and a genuine finding can share one body, and classifying the round on the marker
alone would have discarded a valid blocking issue.

Re-requesting review at the new head, per the loop's restart-at-CodeRabbit rule.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Restarting the review loop at the new head 27efbd36, which carries the fix for the blocking
finding: both the unsigned ref and the signed positive control are now matched against the node's
running verification rules before either is pulled, and an unmatched signed control is
INCONCLUSIVE with nothing pulled. 22 cases green.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@devantler: I will review the updated changes at 27efbd36.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

All 28 check-runs are terminal success or skip at d10d481d, including required CI, manifest validation, publication/matcher controls, and security analysis; the PR is current with main and has zero review threads. Requesting one current-head review.

Please focus on whether the signed-positive-control and unsigned-ref refusal still establish an attributable image-verification verdict after the base merges, and whether any cleanup or tri-state path can overstate PASS.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata ==='
gh pr view 3732 --repo devantler-tech/platform --json number,baseRefName,headRefName,headRefOid,files \
  --jq '{number,baseRefName,headRefName,headRefOid,files:[.files[].path]}'

printf '%s\n' '=== Merge base and changed paths ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s\nhead=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD

printf '%s\n' '=== Probe file AST outline ==='
ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true

printf '%s\n' '=== Probe implementation ==='
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,460p'

printf '%s\n' '=== Probe test AST outline ==='
ast-grep outline scripts/tests/test-probe-image-signature-enforcement.sh --items all || true

printf '%s\n' '=== Probe tests ==='
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,560p'

printf '%s\n' '=== Dedicated workflow ==='
workflow=$(fd -a -t f 'probe-image-signature-enforcement.yaml' .github/workflows | head -n 1 || true)
if [ -n "$workflow" ]; then
  nl -ba "$workflow"
fi

printf '%s\n' '=== Current PR changes in reviewed files ==='
git diff --unified=50 "$base" HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Related Talos image and rule configuration ==='
rg -n -C 6 --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  '(ImageVerificationConfigController|imagePattern|image (list|pull|remove)|get imageverificationrules|imageverificationrules)' \
  scripts .github talos 2>/dev/null || true

Length of output: 156435


@devantler Review complete for d10d481d.

I found no new issues.

The signed positive control and unsigned refusal establish the intended verdict. Both refs must match live running rules before either pull. The probe rejects unmatched and cached refs as INCONCLUSIVE. It also treats a non-verification refusal and a failed signed control as INCONCLUSIVE.

The cleanup trap preserves the original exit status. It removes only refs for which the probe attempted a pull. Cleanup failure cannot convert PASS, FAIL, or INCONCLUSIVE into another verdict.

You are interacting with an AI system.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Current-head user evaluation — ready at d10d481

I evaluated the operator-facing probe at the exact current head d10d481 in an isolated checkout.

  • ShellCheck is clean and all 22 behavioural cases pass.
  • I ran the real probe entrypoint against a controlled talosctl boundary and observed all three user-visible outcomes: a verification refusal plus successful signed control returns PASS and exit 0; an accepted unsigned ref returns FAIL and exit 1; an unrelated registry refusal returns INCONCLUSIVE and exit 3.
  • The default cleanup removed only attempted refs and did not overwrite any of those verdicts.
  • The dormant workflow remains manual-only and confirmation-gated.

This evaluates the shipped probe as its operator without touching production. It deliberately does not claim that production enforcement has now been observed: running the probe against a real node remains the separately authorised observation tracked by #3336.

At this head all 28 check-runs are terminal success or skip, the branch contains current main, there are zero review threads or non-thread findings, and CodeRabbit completed a substantive exact-head review with no new issues.

@devantler
devantler marked this pull request as ready for review September 12, 2026 18:27
@devantler
devantler added this pull request to the merge queue Sep 12, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 12, 2026
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Merge queue result — parked on live incident #3065

This exact head d10d481 was promoted and entered the queue at position 1. Merge-group run 34711309269 passed every speculative configuration and security validation, then its production deploy failed on three orphaned GHCR/Flux fences left by cancelled run 34710276659; the heal path failed on the same fences. GitHub evicted this PR and main remains 491d5ef.

The PR head is unchanged, current with main, and remains CLEAN. This is not a code failure in this PR. The live blocker is recorded with exact run, holder, Lease, and suspended-Kustomization evidence on #3065.

Per the production runbook I am not re-enqueueing into the same failure. After the maintainer performs Scenario 11 recovery, verifies no fence remains, and gets a green CD deployment of main, this reviewed head can be rebound and enqueued again.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

The 18:16Z request came back as a chat reply rather than a review. It carries a "Review complete" line, but no review object or summary exists at this head, so it does not satisfy the review gate. This PR is parked on #3065, so a current-head review now will have it ready to re-enqueue once the production fence is released.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@devantler: I will run a full review for the current head d10d481dcb5db989548efbbaeedac54c0039bbb2.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 40 minutes.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

Retrying after the 20:21Z rate-limit refusal. All checks are green at this head; a current-head review is the remaining gate before this goes back to the merge queue.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Your plan includes PR reviews subject to rate limits. Reviews are available now.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@codex review

CodeRabbit acknowledged the 21:01Z full-review request but produced no review in over half an hour, after refusing the previous round on its rate limit, so this moves to the next review lane. All checks are green at this head, and the production fence that evicted it from the merge queue has cleared.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-13T00:51:32.335679Z 444554b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d10d481dcb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/probe-image-signature-enforcement.yaml Outdated
Comment thread scripts/probe-image-signature-enforcement.sh Outdated
@devantler
devantler marked this pull request as draft September 12, 2026 21:48
…e signed control

A signed control under a different first-match rule cannot exclude a rule that refuses every image it governs, so the probe could PASS on a broken catch-all. Rules are now matched in id (declaration) order and differing rules are INCONCLUSIVE before any pull. Cleanup no longer removes the signed control, which could race a pod on the schedulable node; only the unsigned throwaway is removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

Fixes both Codex findings on b8cde165; all checks are green at this head.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata and reviewed head ==='
gh pr view 3732 --repo devantler-tech/platform \
  --json number,baseRefName,headRefName,headRefOid,files,commits \
  --jq '{number,baseRefName,headRefName,headRefOid,files:[.files[].path],commits:[.commits[]|{oid,messageHeadline}]}'

printf '%s\n' '=== Merge base and complete PR changes ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s\nhead=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD
git diff --unified=70 "$base" HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Delta since the prior reviewed head ==='
git diff --unified=90 b8cde1652a0242f794f80d706b1545273e52b714 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Probe structure and implementation ==='
ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,620p'

printf '%s\n' '=== Probe test structure and test source ==='
ast-grep outline scripts/tests/test-probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,860p'

printf '%s\n' '=== Dedicated probe workflow ==='
workflow="$(fd -a -t f 'probe-image-signature-enforcement.yaml' .github/workflows | head -n1 || true)"
if [[ -n "$workflow" ]]; then
  nl -ba "$workflow"
fi

printf '%s\n' '=== Production mutation workflows and concurrency ==='
rg -n -C 7 --glob '*.yaml' --glob '*.yml' \
  'prod-deploy|concurrency:|talosctl|kubectl|flux (reconcile|suspend|resume)|image (pull|remove)' \
  .github/workflows

printf '%s\n' '=== Live rules, reference normalization, and refusal classification ==='
rule_file="$(fd -a -t f 'verify-first-party-images.yaml' talos | head -n1 || true)"
if [[ -n "$rule_file" ]]; then
  nl -ba "$rule_file"
fi
rg -n -C 8 --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  'ref_repository|match_rule|is_verification_refusal|imagePattern|ImageVerificationConfigController|imageverificationrules|unsigned_image|signed_image|pulled' \
  scripts talos .github 2>/dev/null || true

printf '%s\n' '=== Static shell validation ==='
bash -n scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s bash scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
else
  echo 'shellcheck unavailable'
fi

printf '%s\n' '=== GitHub check status ==='
gh pr checks 3732 --repo devantler-tech/platform || true

Length of output: 203050


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Commit range and remediation commits ==='
git log --oneline --decorate b8cde1652a0242f794f80d706b1545273e52b714..HEAD
git show --stat --oneline HEAD
git diff --check b8cde1652a0242f794f80d706b1545273e52b714 HEAD

printf '%s\n' '=== Exact remediation diff ==='
git diff --unified=120 b8cde1652a0242f794f80d706b1545273e52b714 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml

printf '%s\n' '=== Probe execution and cleanup paths ==='
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '250,500p'

printf '%s\n' '=== Behavioral cases around rule selection, error classification, and cleanup ==='
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '300,620p'

printf '%s\n' '=== PR discussion since prior reviewed head ==='
gh api 'repos/devantler-tech/platform/issues/3732/comments?per_page=100' \
  --jq '.[] | select(.body | contains("Codex") or contains("codex") or contains("f114299d")) | {user:.user.login,created_at,body}' || true

printf '%s\n' '=== Workflow syntax and production-lock scope ==='
nl -ba .github/workflows/probe-image-signature-enforcement.yaml | sed -n '1,180p'

Length of output: 95379


@devantler Review complete for f114299d8a2c793c11354ecf806e13c87a789294.

I found no new issues.

The preflight now requires both controls to select the same first-match running rule. It returns INCONCLUSIVE before either pull when they select different rules. Sorting by rule ID preserves Talos declaration order when the resource stream order differs.

The cleanup path now removes only the unsigned throwaway ref. It preserves the probe exit status and does not remove the signed control after a successful pull.

The behavioral cases cover the new rule-selection and cleanup behavior. Static Bash validation, ShellCheck, and whitespace validation completed without findings.

You are interacting with an AI system.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@codex review

CodeRabbit answered this head as a chat reply, not a review. The review gate does not accept that verdict wording, so this moves to the next lane. This head fixes both findings from your review of b8cde165. The two controls must now select the same first-match rule, taken in declaration order, and the signed control is never removed. All checks are green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f114299d8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/probe-image-signature-enforcement.sh
Comment thread scripts/probe-image-signature-enforcement.sh
…e-insensitively

talosctl reads a comma-separated node as several targets, so a node list fanned the probe out across production nodes and a mixed result could still PASS; --node now rejects commas and whitespace before any talosctl call. Registry domains are now lowercased for rule matching, as Talos matches them, so an upper-case domain no longer reads as unmatched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

Fixes both Codex findings on f114299d; all checks are green at this head.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata and current head ==='
gh pr view 3732 --repo devantler-tech/platform \
  --json number,baseRefName,headRefName,headRefOid,files,commits \
  --jq '{number,baseRefName,headRefName,headRefOid,files:[.files[].path],commits:[.commits[]|{oid,messageHeadline}]}'

printf '%s\n' '=== Merge base and complete pull request changes ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s\nhead=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD
git diff --unified=70 "$base" HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Delta since previous CodeRabbit-reviewed head ==='
git diff --unified=100 f114299d8a2c793c11354ecf806e13c87a789294 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Probe structure and implementation ==='
ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,680p'

printf '%s\n' '=== Test structure and behavioral cases ==='
ast-grep outline scripts/tests/test-probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,960p'

printf '%s\n' '=== Dedicated workflow ==='
workflow="$(fd -a -t f 'probe-image-signature-enforcement.yaml' .github/workflows | head -n1 || true)"
if [[ -n "$workflow" ]]; then
  nl -ba "$workflow"
fi

printf '%s\n' '=== Relevant live rule configuration and workflow locks ==='
rule_file="$(fd -a -t f 'verify-first-party-images.yaml' talos | head -n1 || true)"
if [[ -n "$rule_file" ]]; then
  nl -ba "$rule_file"
fi
rg -n -C 7 --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  'ref_repository|match_rule|is_verification_refusal|imagePattern|ImageVerificationConfigController|imageverificationrules|prod-deploy|concurrency:' \
  scripts talos .github 2>/dev/null || true

printf '%s\n' '=== Static checks ==='
bash -n scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s bash scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
else
  echo 'shellcheck unavailable'
fi
git diff --check "$base" HEAD

printf '%s\n' '=== Pull request check status ==='
gh pr checks 3732 --repo devantler-tech/platform || true

Length of output: 164583


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Current head and remediation commits ==='
git rev-parse HEAD
git log --oneline --decorate f114299d8a2c793c11354ecf806e13c87a789294..HEAD
git diff --check f114299d8a2c793c11354ecf806e13c87a789294 HEAD
git diff --unified=120 f114299d8a2c793c11354ecf806e13c87a789294 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml

printf '%s\n' '=== Cached-reference matching implementation and test coverage ==='
rg -n -C 10 --glob '*.sh' \
  'ref_is_cached|image_list|ALREADY in node|upper_unsigned|upper_signed|lowercase_registry_domain|ref_repository' \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh

printf '%s\n' '=== Talosctl image list output references in repository ==='
rg -n -C 5 --glob '*.md' --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  'image list|image list --namespace|ghcr.io|GHCR.IO' \
  README.md docs scripts talos .github 2>/dev/null | head -500

Length of output: 102936


@devantler Review complete for aa5190d2b43b33c96b28e3aef97f26465ccb81d0.

I found no new issues.

The node validation rejects comma-separated and whitespace-separated target lists before any Talos command runs. This preserves the single-node scope and prevents results from separate nodes from producing one verdict.

lowercase_registry_domain() normalizes only the registry domain before rule matching. It preserves the repository path and works with the existing repository and tag/digest normalization.

The existing preflight, cache guard, refusal attribution, signed positive control, and cleanup paths still fail closed to INCONCLUSIVE where the probe cannot support PASS.

Static Bash validation, ShellCheck, and whitespace validation completed without findings. The listed PR checks are passing or skipped.

You are interacting with an AI system.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@codex review

CodeRabbit answered this head as a chat reply, not a review. The review gate does not accept that verdict wording, so this moves to the next lane. This head fixes both findings from your review of f114299d: --node now rejects comma- and whitespace-separated lists before any talosctl call, and registry domains are lowercased for rule matching. All checks are green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa5190d2b4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/probe-image-signature-enforcement.sh
Comment thread .github/workflows/probe-image-signature-enforcement.yaml
…robe's talosctl install

Lowercasing only the registry domain for rule matching let an upper-case ref miss its cached lowercase twin, so a cached pull could skip verification and report PASS. Refs whose name is not canonical lowercase are now a usage error before any talosctl call, and the case helper is removed. The probe workflow is added to the setup-talosctl call-site guard, which previously never inspected it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

Fixes both Codex findings on aa5190d2; all checks are green at this head.

@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata and current head ==='
gh pr view 3732 --repo devantler-tech/platform \
  --json number,baseRefName,headRefName,headRefOid,files,commits \
  --jq '{number,baseRefName,headRefName,headRefOid,files:[.files[].path],commits:[.commits[]|{oid,messageHeadline}]}'

printf '%s\n' '=== Merge base and changed files ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s\nhead=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD
git diff --check "$base" HEAD

printf '%s\n' '=== Full probe implementation map ==='
ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true
printf '%s\n' '=== Full probe implementation ==='
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,760p'

printf '%s\n' '=== Full behavioral test implementation ==='
ast-grep outline scripts/tests/test-probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,1100p'

printf '%s\n' '=== Current delta since prior reviewed head ==='
git diff --unified=120 aa5190d2b43b33c96b28e3aef97f26465ccb81d0 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Dedicated workflow ==='
workflow="$(fd -a -t f 'probe-image-signature-enforcement.yaml' .github/workflows | head -n1 || true)"
if [[ -n "$workflow" ]]; then
  nl -ba "$workflow"
fi

printf '%s\n' '=== Live rules and all relevant image/rule consumers ==='
rule_file="$(fd -a -t f 'verify-first-party-images.yaml' talos | head -n1 || true)"
if [[ -n "$rule_file" ]]; then
  nl -ba "$rule_file"
fi
rg -n -C 8 --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  'ref_repository|lowercase_registry_domain|match_rule|ref_is_cached|is_verification_refusal|imagePattern|ImageVerificationConfigController|imageverificationrules|image (list|pull|remove)|prod-deploy|concurrency:' \
  scripts talos .github 2>/dev/null || true

printf '%s\n' '=== Static validation ==='
bash -n scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s bash scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh
else
  echo 'shellcheck unavailable'
fi

printf '%s\n' '=== Check status ==='
gh pr checks 3732 --repo devantler-tech/platform || true

Length of output: 216824


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Latest remediation commit and complete patch ==='
git show --stat --oneline HEAD
git show --format=fuller --find-renames --find-copies --unified=120 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  scripts/tests/test-setup-talosctl.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Test setup changes and CI test wiring ==='
nl -ba scripts/tests/test-setup-talosctl.sh | sed -n '1,360p'
rg -n -C 6 --glob '*.yaml' --glob '*.yml' \
  'test-probe-image-signature-enforcement|probe-image-signature-enforcement|test-setup-talosctl' \
  .github/workflows

printf '%s\n' '=== Argument parsing and reference normalization call sites ==='
rg -n -C 8 --glob '*.sh' \
  'no tag or digest|canonical lowercase|ref_repository\(|image list|image pull|without_probe_refs\(' \
  scripts/probe-image-signature-enforcement.sh scripts/tests/test-probe-image-signature-enforcement.sh

printf '%s\n' '=== Current branch differences outside probe files ==='
base="$(git merge-base HEAD origin/main)"
git diff --name-only "$base" HEAD | while IFS= read -r file; do
  case "$file" in
    scripts/probe-image-signature-enforcement.sh|scripts/tests/test-probe-image-signature-enforcement.sh|scripts/tests/test-setup-talosctl.sh|.github/workflows/probe-image-signature-enforcement.yaml|.github/workflows/ci.yaml) ;;
    *) printf '%s\n' "$file" ;;
  esac
done

Length of output: 88241


@devantler Full review complete for 7db24990896de60d39d6adbf8719f47b96e59d08.

I found no new issues.

The new lowercase validation runs before any talosctl call. It rejects non-canonical registry or repository names. This prevents a mixed-case reference from missing its lowercase cached equivalent and producing an unfounded PASS.

The new behavioral cases cover both controls. They require a usage error and no image pull when either reference has uppercase characters in its registry or repository name.

The setup-talosctl call-site guard now includes the probe workflow. Bash syntax validation, ShellCheck, and whitespace validation completed without findings. The listed GitHub checks are passing or skipped.

You are interacting with an AI system.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@codex review

CodeRabbit answered this head as a chat reply ("Full review complete for" / "no new issues"), and the review gate does not accept that wording, so this moves to the next lane. This head fixes both findings from your review of aa5190d2: refs whose name is not canonical lowercase are now a usage error before any talosctl call, and the probe workflow is on the setup-talosctl call-site guard. All checks are green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7db2499089

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yaml
The probe workflow is inspected by the setup-talosctl call-site guard, but its own path was not in the k8s filter, so a PR changing only that workflow skipped the guard and the probe suite. The workflow path now joins the probe script and test in the filter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai full review

Fixes the Codex finding on 7db24990; all checks are green at this head.

@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Pull request metadata and current head ==='
gh pr view 3732 --repo devantler-tech/platform \
  --json number,baseRefName,headRefName,headRefOid,files,commits \
  --jq '{number,baseRefName,headRefName,headRefOid,files:[.files[].path],commits:[.commits[]|{oid,messageHeadline}]}'

printf '%s\n' '=== Merge base, changed paths, and whitespace validation ==='
base="$(git merge-base HEAD origin/main)"
printf 'base=%s\nhead=%s\n' "$base" "$(git rev-parse HEAD)"
git diff --name-status "$base" HEAD
git diff --check "$base" HEAD

printf '%s\n' '=== Delta since prior CodeRabbit-reviewed head ==='
git diff --unified=120 7db24990896de60d39d6adbf8719f47b96e59d08 HEAD -- \
  scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  scripts/tests/test-setup-talosctl.sh \
  .github/workflows/probe-image-signature-enforcement.yaml \
  .github/workflows/ci.yaml

printf '%s\n' '=== Full probe implementation map and source ==='
ast-grep outline scripts/probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/probe-image-signature-enforcement.sh | sed -n '1,850p'

printf '%s\n' '=== Full behavioral-test map and source ==='
ast-grep outline scripts/tests/test-probe-image-signature-enforcement.sh --items all || true
nl -ba scripts/tests/test-probe-image-signature-enforcement.sh | sed -n '1,1250p'

printf '%s\n' '=== Related test setup and workflow source ==='
nl -ba scripts/tests/test-setup-talosctl.sh | sed -n '1,420p'
workflow="$(fd -a -t f 'probe-image-signature-enforcement.yaml' .github/workflows | head -n1 || true)"
if [[ -n "$workflow" ]]; then
  nl -ba "$workflow"
fi

printf '%s\n' '=== Image-verification configuration and all relevant call sites ==='
rule_file="$(fd -a -t f 'verify-first-party-images.yaml' talos | head -n1 || true)"
if [[ -n "$rule_file" ]]; then
  nl -ba "$rule_file"
fi
rg -n -C 8 --glob '*.sh' --glob '*.yaml' --glob '*.yml' \
  'ref_repository|lowercase_registry_domain|match_rule|ref_is_cached|is_verification_refusal|imagePattern|ImageVerificationConfigController|imageverificationrules|image (list|pull|remove)|prod-deploy|concurrency:|setup-talosctl' \
  scripts talos .github 2>/dev/null || true

printf '%s\n' '=== Static shell validation ==='
bash -n scripts/probe-image-signature-enforcement.sh \
  scripts/tests/test-probe-image-signature-enforcement.sh \
  scripts/tests/test-setup-talosctl.sh
if command -v shellcheck >/dev/null 2>&1; then
  shellcheck -s bash \
    scripts/probe-image-signature-enforcement.sh \
    scripts/tests/test-probe-image-signature-enforcement.sh \
    scripts/tests/test-setup-talosctl.sh
else
  echo 'shellcheck unavailable'
fi

printf '%s\n' '=== Current pull-request checks ==='
gh pr checks 3732 --repo devantler-tech/platform || true

Length of output: 236233


@devantler Full review complete for 444554b45a6b9bcf6d982fa6a4ff66da00273f89.

I found no new issues.

The current change adds .github/workflows/probe-image-signature-enforcement.yaml to the k8s path filter. Therefore, a change to the probe workflow alone now runs scripts/tests/test-setup-talosctl.sh. That test verifies that the workflow invokes .github/scripts/setup-talosctl.sh and does not install talosctl directly.

The probe workflow still uses the shared prod-deploy concurrency group. The probe behavior still fails closed to INCONCLUSIVE when its result is not attributable.

Bash syntax validation, ShellCheck, and whitespace validation completed without findings. The listed PR checks passed or were skipped.

You are interacting with an AI system.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@codex review

CodeRabbit answered this head as a chat reply ("Full review complete for" / "no new issues"), and the review gate does not accept that wording, so this moves to the next lane. This head fixes your finding on 7db24990: the probe workflow is now in the k8s path filter, so a change to it alone re-runs the setup-talosctl guard and the probe suite. All checks are green.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 444554b45a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@devantler
devantler marked this pull request as ready for review September 13, 2026 00:53
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Ready. The merge is deliberately held.

Readiness at 444554b45a6b9bcf6d982fa6a4ff66da00273f89:

  • Tested: no failing checks: of the distinct checks, 17 passed and 6 were skipped. They include shellcheck and the probe's behavioural suite, now 31 cases, plus the setup-talosctl call-site guard that now covers this workflow.

  • Reviewed: Codex found no major issues at this head. There are no finding comments and all 9 review threads are resolved. CodeRabbit's replies at recent heads came in a chat wording the review gate does not accept, so Codex is the qualifying review.

  • Evaluated: the probe changes production nodes and ships dormant, so it is not run live here. Observing a real refusal on a node is Prove an unsigned image is refused at pull, then activate the liveness check #3336's scope, as this PR states. I evaluated it the way an operator would meet it: the suite drives the real script end to end against a fake talosctl. The script refuses to run without --confirm, and every usage error stops before any node call. The verdicts cover each case the review rounds raised:

    • a ref echoed back in an error message
    • TLS and x509 wording
    • repository-only rule matching
    • both controls sharing one rule, in declaration order
    • the signed control never being removed
    • node lists
    • non-lowercase refs

    In each case where the evidence is not attributable, the verdict stays INCONCLUSIVE. Each of those fixes also has a case that fails again when the fix is removed.

Why it is not queued yet: merging here runs the production deploy on the same prod-deploy lock the Wedding database recovery uses. That recovery is still being worked (draft #3750), so the merge waits, exactly as #3741's does.

@devantler
devantler added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit ca7dfd0 Sep 13, 2026
29 checks passed
@devantler
devantler deleted the claude/probe-image-signature-enforcement-3653 branch September 13, 2026 02:39
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Provide the reviewed throwaway probe path for image-signature enforcement

1 participant