Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
994fca2
feat: implement issue #1267 — Standards sweep and compliance audit ac…
don-petry Oct 9, 2026
b084791
fix(reviews): resolve #1269 review threads (pin verdict, tests, docs)
don-petry Oct 9, 2026
c9e8dfd
Merge branch 'main' into dev-lead/issue-1267-20261009-1929
don-petry Oct 9, 2026
6de42d0
fix(reviews): strip comments in sweep pin check; capture ring_accepte…
don-petry Oct 9, 2026
c14c054
fix(reviews): assert warning severity in failed-probe test
don-petry Oct 9, 2026
b45c575
fix(reviews): use [[ ]] on PR-added tests; single check_id constant i…
don-petry Oct 9, 2026
5900e4c
fix(reviews): force decimal in ring_tier_channel_major numeric compare
don-petry Oct 9, 2026
05e0e05
fix(reviews): add header comments to touched test helpers; drop blank…
don-petry Oct 10, 2026
d2acfdd
fix(bot): enforce major-scoped v-form for RING pins without channel tags
don-petry Oct 10, 2026
521b4a8
docs: update ring_pin_current docstring for #1267 bare-pin rejection
don-petry Oct 10, 2026
154dbbb
Revert "docs: update ring_pin_current docstring for #1267 bare-pin re…
don-petry Oct 10, 2026
0f316fd
Revert "fix(bot): enforce major-scoped v-form for RING pins without c…
don-petry Oct 10, 2026
882cbbe
Merge branch 'main' into dev-lead/issue-1267-20261009-1929
don-petry Oct 10, 2026
201c5cb
fix(bot): allow bare dev-lead/<tier> pins to reach ring_pin_current i…
don-petry Oct 10, 2026
0900dbb
fix(bot): respect bare_ok flag when reporting non-compliant pins in g…
don-petry Oct 10, 2026
9b3e262
fix(bot): extract channel from bare uses pin in dev-lead stub validation
don-petry Oct 10, 2026
685b1ee
fix(reviews): satisfy Sonar S7688/S1066 and localize bare_channel in …
don-petry Oct 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 80 additions & 21 deletions scripts/compliance-audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,9 @@ stub_pin_acceptable() {
# through to the drift finding. Anchored to start-of-line so a `# uses: …` comment
# never counts. Pure — extracts the pinned ref, reads its major with
# ring_pinned_major(), and checks it against ring_canonical_ref(…, major).
# FORM gate only: whether M is the CURRENT major for the tier is decided by
# ring_pin_current (lib/ring-pins.sh), which check_centralized_workflow_stubs
# also requires (#1267).
ring_major_form_acceptable() {
local decoded="$1" reusable="$2" chan="$3" repo="$4"
local esc_reusable; esc_reusable=$(escape_ere "$reusable")
Expand All @@ -1728,7 +1731,6 @@ ring_major_form_acceptable() {
# ring_tier_for_repo(), ring_canonical_ref() and ring_legacy_csv() are provided by
# lib/ring-pins.sh (sourced above) — the single source of truth shared with the
# deploy sweep so the audit and the deploy never disagree on a stub's pin (#482).

check_centralized_workflow_stubs() {
local repo="$1"

Expand Down Expand Up @@ -1806,26 +1808,58 @@ check_centralized_workflow_stubs() {
[ -z "$decoded" ] && continue

# Compliance rule (major-scoped-channels epic #657 F5, #861):
# RING reusables MUST pin the major-scoped `<name>/v<M>-<tier>` form — any
# major M whose tier matches the repo (ring_major_form_acceptable). A bare
# RING reusables MUST pin the major-scoped `<name>/v<M>-<tier>` form whose
# tier matches the repo (ring_major_form_acceptable). A bare
# `<name>/<tier>` pin is now drift: the fleet has migrated onto the v-form,
# so the bare grace (stub_pin_acceptable) no longer applies to the rings.
# Non-RING reusables (fixed-pin entries) keep the exact/legacy match via
# stub_pin_acceptable.
# Both helpers anchor to start-of-line so a `# uses: …` comment never counts;
# a v-form pinned to the WRONG tier stays drift.
if { [ "$is_ring" = 1 ] && ring_major_form_acceptable "$decoded" "$reusable" "$chan" "$repo"; } \
|| { [ "$is_ring" != 1 ] && stub_pin_acceptable "$decoded" "$reusable" "$canonical" "$legacy"; }; then
# #1267: the RING v-form must also be on the CURRENT channel major for the
# repo's tier (ring_pin_current — the same verdict the deploy sweep uses).
# A tier-correct pin on a superseded major is drift; a failed tag probe
# fails closed (the stub is not declared compliant).
local esc_reusable pinned_ref="" pin_rc=0
esc_reusable=$(escape_ere "$reusable")
if [[ "$is_ring" = 1 ]]; then
pinned_ref=$(printf '%s\n' "$decoded" \
| sed -nE "s#^[[:space:]]*uses:[[:space:]]*petry-projects/\\.github/\\.github/workflows/${esc_reusable}\\.yml@([^[:space:]]+).*#\\1#p" \
| head -n1)
ring_pin_current "$ORG/.github" "$chan" "$repo" "$pinned_ref" || pin_rc=$?
Comment thread
don-petry marked this conversation as resolved.
fi
# With no channel tag cut yet, ring_pin_current expects (and accepts) the bare
# `<base>/<tier>`; follow its verdict rather than also demanding the v-form.
local bare_ok=0
[[ "$is_ring" = 1 ]] && [[ "$pin_rc" -eq 0 ]] && [[ "$RING_EXPECTED_REF" != */v[0-9]* ]] && bare_ok=1
if { [[ "$is_ring" = 1 ]] && [[ "$pin_rc" -eq 0 ]] && { [[ "$bare_ok" = 1 ]] || ring_major_form_acceptable "$decoded" "$reusable" "$chan" "$repo"; }; } \
|| { [[ "$is_ring" != 1 ]] && stub_pin_acceptable "$decoded" "$reusable" "$canonical" "$legacy"; }; then
continue
fi

if [[ "$pin_rc" -eq 2 ]]; then
add_finding "$repo" "ci-workflows" "non-stub-$wf" "warning" \
"Could not verify that centralized workflow \`$wf\` pins the current \`${chan}\` channel: the channel-tag listing on \`$ORG/.github\` could not be read. Failing closed — the stub is not treated as compliant. Re-run the audit once the tag listing is readable." \
"standards/ci-standards.md#reusable-workflow-versioning--the-stable-channel"
continue
fi

# Determine why it's non-compliant for a more actionable message. For RING
# reusables the expected pin is the major-scoped v-form `<name>/v<M>-<tier>`
# (major-agnostic on tier, #657 F5); non-ring keeps the fixed canonical ref.
local esc_reusable why expected_pin="$canonical"
esc_reusable=$(escape_ere "$reusable")
[ "$is_ring" = 1 ] && expected_pin="${chan}/v<M>-$(ring_tier_for_repo "$chan" "$repo")"
if echo "$decoded" | grep -qE "^[[:space:]]*uses:[[:space:]]*petry-projects/\\.github/\\.github/workflows/${esc_reusable}\\.yml@"; then
# reusables the expected pin is the repo tier's current major-scoped channel
# (RING_EXPECTED_REF from ring_pin_current, #1267); non-ring keeps the fixed
# canonical ref.
local why expected_pin="$canonical"
[[ "$is_ring" = 1 ]] && expected_pin="$RING_EXPECTED_REF"
if [[ "$is_ring" = 1 ]] && [[ "${RING_EXPECTED_RESOLVABLE:-1}" = 0 ]]; then
why="pins \`${pinned_ref}\`, but no \`${chan}\` channel tag has been cut for this repo's ring tier yet, so there is no resolvable ref to pin"
add_finding "$repo" "ci-workflows" "non-stub-$wf" "error" \
"Centralized workflow \`$wf\` $why. Wait for a channel tag to be cut for this tier (or re-tier the repo); do not re-pin to another tier's channel." \
"standards/ci-standards.md#centralization-tiers"
continue
fi
if [[ "$is_ring" = 1 ]] && ring_vform_tier_aligned "$pinned_ref" "$chan" "$repo"; then
why="pins \`${pinned_ref}\`; expected \`${expected_pin}\` — a superseded channel major is drift (promotion no longer moves it)"
elif [[ "$bare_ok" = 0 ]] && echo "$decoded" | grep -qE "^[[:space:]]*uses:[[:space:]]*petry-projects/\\.github/\\.github/workflows/${esc_reusable}\\.yml@"; then
why="references the reusable but is not pinned to the major-scoped channel \`@${expected_pin}\` (org standard — a bare \`@${canonical}\` tier pin is drift)"
elif echo "$decoded" | grep -qF "petry-projects/.github/.github/workflows/${reusable}"; then
why="references the reusable but the \`uses:\` line does not match the canonical stub"
Expand Down Expand Up @@ -1856,6 +1890,7 @@ check_centralized_workflow_stubs() {
# ---------------------------------------------------------------------------
check_dev_lead_stub() {
local repo="$1"
local check_id="dev-lead-stub-pin"

# .github holds the template (exercised by the reusable's own CI) and
# .github-private runs the workflow inline rather than as a caller stub.
Expand All @@ -1875,19 +1910,40 @@ check_dev_lead_stub() {
# or `@<sha>` is NOT a channel and is intentionally rejected — callers pin the
# moving channel so rollout/rollback is a single central tag move.
# Major-scoped channels (#657 F5, #861): the channel MUST carry the `v<M>-`
# major prefix — a bare `dev-lead/stable` is now drift; only `dev-lead/v<M>-<tier>`
# (any major) is accepted, mirroring the RING reusables above.
if ! printf '%s\n' "$decoded" | grep -qE "^[[:space:]]*uses:[[:space:]]*petry-projects/\\.github-private/\\.github/workflows/dev-lead-reusable\\.yml@dev-lead/v[0-9]+-(stable|next|ring[0-9]+)([[:space:]]|$)"; then
add_finding "$repo" "ci-workflows" "dev-lead-stub-pin" "error" \
"The \`dev-lead.yml\` caller stub must pin a major-scoped \`dev-lead\` channel tag — \`petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@dev-lead/v<M>-<channel>\` where <channel> is \`stable\` (default), \`next\`, or \`ring<N>\` (a bare \`dev-lead/<channel>\` tier pin is drift). Re-sync from \`standards/workflows/dev-lead.yml\`." \
# major prefix — a bare `dev-lead/stable` is now drift.
# #1267: the v-form must also be the CURRENT channel for the repo's tier —
# `dev-lead/v<M>-<tier>` with M the highest major tagged for that tier
# (ring_pin_current, the same verdict the deploy sweep uses). A pin on a
# superseded major (e.g. `dev-lead/v1-stable` once `dev-lead/v139-stable`
# exists) or on another repo's tier is drift; a failed tag probe fails closed.
if ! printf '%s\n' "$decoded" | grep -qE "^[[:space:]]*uses:[[:space:]]*petry-projects/\\.github-private/\\.github/workflows/dev-lead-reusable\\.yml@dev-lead/(v[0-9]+-)?(stable|next|ring[0-9]+)([[:space:]]|$)"; then
add_finding "$repo" "ci-workflows" "$check_id" "error" \
"The \`dev-lead.yml\` caller stub must pin a \`dev-lead\` channel tag — \`petry-projects/.github-private/.github/workflows/dev-lead-reusable.yml@dev-lead/v<M>-<channel>\` where <channel> is \`stable\` (default), \`next\`, or \`ring<N>\`. A bare \`dev-lead/<channel>\` tier pin is allowed when the agent has no channel tags. Re-sync from \`standards/workflows/dev-lead.yml\`." \
"standards/ci-standards.md#dev-lead-agent"
else
local dl_pinned dl_rc=0
dl_pinned=$(printf '%s\n' "$decoded" | sed -nE 's#^[[:space:]]*uses:[[:space:]]*petry-projects/\.github-private/\.github/workflows/dev-lead-reusable\.yml@(dev-lead/[^[:space:]]+).*#\1#p' | head -n1)
ring_pin_current "$ORG/.github-private" "dev-lead" "$repo" "$dl_pinned" || dl_rc=$?
if [[ "$dl_rc" -eq 1 ]] && [[ "${RING_EXPECTED_RESOLVABLE:-1}" = 0 ]]; then
add_finding "$repo" "ci-workflows" "$check_id" "error" \
"The \`dev-lead.yml\` caller stub pins \`${dl_pinned}\`, but no \`dev-lead\` channel tag has been cut for this repo's ring tier yet, so there is no resolvable ref to pin. Wait for a tag to be cut for this tier (or re-tier the repo); do not re-pin to another tier's channel." \
"standards/ci-standards.md#dev-lead-agent"
elif [[ "$dl_rc" -eq 1 ]]; then
add_finding "$repo" "ci-workflows" "$check_id" "error" \
"The \`dev-lead.yml\` caller stub pins \`${dl_pinned}\`; expected \`${RING_EXPECTED_REF}\` — the current \`dev-lead\` channel for this repo's ring tier. A superseded channel major (or another tier's channel) is drift: promotion no longer moves it, so the repo never receives a release. Re-sync from \`standards/workflows/dev-lead.yml\` (the standards sweep re-pins it in place)." \
"standards/ci-standards.md#dev-lead-agent"
elif [[ "$dl_rc" -eq 2 ]]; then
add_finding "$repo" "ci-workflows" "$check_id" "warning" \
"Could not verify that the \`dev-lead.yml\` caller stub (\`${dl_pinned}\`) pins the current \`dev-lead\` channel: the channel-tag listing on \`$ORG/.github-private\` could not be read. Failing closed — the stub is not treated as compliant. Re-run the audit once the tag listing is readable." \
"standards/ci-standards.md#dev-lead-agent"
fi
fi

# 2) agent_ref must be threaded through to pin the same channel inside the
# reusable's own script/prompt checkout (prevents split-brain on promotion).
# Same major-scoped channel form as the uses: pin above; must match the uses:
# channel exactly — including its major, so a `v3-stable` uses pin with a
# `v2-stable` agent_ref is caught.
# Must match the uses: channel exactly — including its major (if present).
# When uses is a v-form (e.g. v3-stable), agent_ref must match it.
# When uses is bare (e.g. stable), agent_ref must also be bare.
uses_channel=$(printf '%s\n' "$decoded" | sed -nE 's#^[[:space:]]*uses:[[:space:]]*petry-projects/\.github-private/\.github/workflows/dev-lead-reusable\.yml@dev-lead/(v[0-9]+-(stable|next|ring[0-9]+))([[:space:]]|$).*#\1#p')
if [ -n "$uses_channel" ]; then
if ! printf '%s\n' "$decoded" | grep -qE "^[[:space:]]*agent_ref:[[:space:]]*dev-lead/$uses_channel([[:space:]]|$)"; then
Expand All @@ -1896,9 +1952,12 @@ check_dev_lead_stub() {
"standards/ci-standards.md#dev-lead-agent"
fi
else
if ! printf '%s\n' "$decoded" | grep -qE "^[[:space:]]*agent_ref:[[:space:]]*dev-lead/v[0-9]+-(stable|next|ring[0-9]+)([[:space:]]|$)"; then
local bare_channel
bare_channel=$(printf '%s\n' "$decoded" | sed -nE 's#^[[:space:]]*uses:[[:space:]]*petry-projects/\.github-private/\.github/workflows/dev-lead-reusable\.yml@dev-lead/(stable|next|ring[0-9]+)([[:space:]]|$).*#\1#p')
if [[ -n "$bare_channel" ]] \
&& ! printf '%s\n' "$decoded" | grep -qE "^[[:space:]]*agent_ref:[[:space:]]*dev-lead/$bare_channel([[:space:]]|$)"; then
add_finding "$repo" "ci-workflows" "dev-lead-stub-agent-ref" "error" \
"The \`dev-lead.yml\` caller stub must pass \`with: agent_ref: dev-lead/v<M>-<channel>\` (\`stable\`, \`next\`, or \`ring<N>\`) so the reusable checks out its own scripts/prompts from the same major-scoped channel. Re-sync from \`standards/workflows/dev-lead.yml\`." \
"The \`dev-lead.yml\` caller stub must pass \`with: agent_ref: dev-lead/$bare_channel\` to match the pinned channel \`$bare_channel\`. Re-sync from \`standards/workflows/dev-lead.yml\`." \
"standards/ci-standards.md#dev-lead-agent"
fi
fi
Expand Down
63 changes: 30 additions & 33 deletions scripts/deploy-standard-workflows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -384,32 +384,28 @@ is_pin_compliant() {
# the bare `<base>/<tier>` OR the major-scoped `<base>/v<M>-<tier>` form (#657
# F5) — post-migration the templates pin the v-form, so both must enter here.
if ring_is_ring_reusable "$base" && [[ "$ref_after" =~ ^${base}/(v[0-9]+-)?(stable|next|ring[0-9]+)$ ]]; then
# Major-scoped channels (#657 F5, #861, #870): the bare-tier grace is now
# major-AWARE, keyed on the CHANNEL major (the highest `<base>/v<M>-<tier>`
# channel tag that exists) — NOT the release major. A bare `<base>/<tier>`
# stub stays compliant only while the agent has NO channel tag (nothing to
# major-scope onto yet). Once a channel tag exists, a bare stub is drift and
# must migrate to the tier's `v<M>-<tier>` form. Using the channel major (not
# the release major) is what keeps dev-lead — release v14, channel v1 — pinned
# to the tag that actually resolves (@dev-lead/v1-<tier>, not @dev-lead/v14-…).
local host major
# Major-scoped channels (#657 F5, #861, #870, #1267): the stub is compliant
# only when it pins the CURRENT channel for its tier — `<base>/v<M>-<tier>`
# where M is the highest major with a channel tag for THAT tier (not the
# release major, and not "any major"). A stub left on a superseded major
# (e.g. `dev-lead/v1-stable` once `dev-lead/v139-stable` exists), a wrong-tier
# v-form, or a bare `<base>/<tier>` once a channel tag exists is drift and is
# re-pinned to the ref emit_ref_for computes from the same helper. While the
# agent has NO channel tag the bare-tier grace still applies. A failed tag
# probe fails closed (never compliant). ring_pin_current is shared with the
# audit so the sweep and the audit cannot disagree.
local host existing_ref
host="$(cut -d/ -f1-2 <<< "$prefix")"
major="$(ring_host_current_channel_major "$host" "$base")" || return 1
if [[ -z "$major" ]]; then
local ref
while IFS= read -r ref; do
[[ -n "$ref" ]] && grep -qF "${prefix}@${ref}" <<< "$existing_content" && return 0
done < <(ring_accepted_refs "$base" "$repo")
fi
# A stub already pinned to the repo's tier-correct `v<M>-<tier>` form (any
# major) is compliant regardless of release state. A WRONG-tier v-form — or a
# bare stub once the agent has a release — is not accepted here and stays drift.
local existing_ref
existing_ref=$(grep -oE "@${base}/[^[:space:]\"']+" <<< "$existing_content" | head -1)
# Only a `uses:` line counts: a comment or `agent_ref:` carrying the current
# tag must not mask a stale `uses:` pin.
# Strip inline YAML comments first and require the `<base>-reusable.yml@` ref,
# so a ref written in a comment or on an unrelated job's `uses:` is ignored.
# `sed -n 1p` (not `head -1`) reads the whole stream, so no writer sees a closed pipe.
existing_ref=$(sed -E 's/[[:space:]]+#.*$//' <<< "$existing_content" \
| grep -E "^[[:space:]]*(-[[:space:]]+)?uses:.*/${base}-reusable\.yml@${base}/" \
| grep -oE "@${base}/[^[:space:]\"']+" | sed -n 1p || true)
existing_ref="${existing_ref#@}"
if [[ -n "$existing_ref" ]] && ring_vform_tier_aligned "$existing_ref" "$base" "$repo"; then
return 0
fi
ring_pin_current "$host" "$base" "$repo" "$existing_ref" && return 0
return 1
fi
fi
Expand Down Expand Up @@ -443,20 +439,21 @@ reusable_host_of() {
# emit_ref_for <template> <repo> -> the channel ref a (re)deployed stub in <repo>
# should pin (#657 F5). For a ring-managed reusable it is the repo's tier channel,
# major-scoped `v<M>-<tier>` when the agent has a CHANNEL tag, else the bare `<tier>`
# form. The major is the CHANNEL major (highest existing `<base>/v<M>-<tier>` tag),
# NOT the release major — so dev-lead (release v14, channel v1) pins the resolving
# `@dev-lead/v1-<tier>`, never the tagless `@dev-lead/v14-<tier>` (#870). Empty for
# a non-ring template (deployed verbatim). Requires GH_TOKEN.
# form. M is the CURRENT channel major for the repo's tier (highest existing
# `<base>/v<M>-<tier>` tag for that tier, #1267) — never the release major (#870),
# and never a major only cut on other tiers. It is RING_EXPECTED_REF from
# ring_pin_current, the same helper is_pin_compliant uses, so the sweep never emits
# a ref its own compliance check would reject. Empty for a non-ring template
# (deployed verbatim). Returns 1 on a failed tag probe. Requires GH_TOKEN.
emit_ref_for() {
local template="$1" repo="$2" base host major
local template="$1" repo="$2" base host rc=0
base="$(reusable_base_of "$template")"
[[ -z "$base" ]] && return 0
ring_is_ring_reusable "$base" || return 0
host="$(reusable_host_of "$template")"
if ! major="$(ring_host_current_channel_major "$host" "$base")"; then
return 1
fi
ring_canonical_ref "$base" "$repo" "$major"
ring_pin_current "$host" "$base" "$repo" "" || rc=$?
[[ "$rc" -eq 2 ]] && return 1
printf '%s' "$RING_EXPECTED_REF"
return 0
}

Expand Down
Loading
Loading