Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 11 additions & 3 deletions scripts/compliance-audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1725,14 +1725,22 @@ stub_extract_blocks() {

# stub_normalize_surface — read a surface block on stdin and canonicalize it for
# comparison: strip trailing ` #…` inline comments and whole-line comments, drop
# blank lines, and collapse schedule cron VALUES to a placeholder (a repo MAY
# retune the cron without it counting as trigger-surface drift — see
# feature-ideation.yml's header). Pure: stdin -> stdout.
# blank lines, and collapse two documented per-repo VALUES to placeholders:
# • schedule cron VALUES — a repo MAY retune the cron without it counting as
# trigger-surface drift (see feature-ideation.yml's header).
# • pr-auto-review's `workflow_run.workflows:` list VALUE — a repo MUST name
# its own CI workflow(s) here (see pr-auto-review.yml's header + TODO), so
# the list value is not repo-locked while the `workflow_run` trigger key and
# the rest of the `on:` surface stay verbatim-compared (#990).
# `workflows:` is a key only under `workflow_run`, which appears in no other
# guarded surface, so the collapse is safe to apply unconditionally. Pure:
# stdin -> stdout.
stub_normalize_surface() {
tr -d '\r' | sed -E \
-e 's/[[:space:]]+#.*$//' \
-e 's/^[[:space:]]*#.*$//' \
-e 's/(- cron:[[:space:]]*).*/\1CRON/' \
-e 's/^([[:space:]]*workflows:[[:space:]]*)\[.*/\1WORKFLOWS/' \
| grep -vE '^[[:space:]]*$' || true
}

Expand Down
84 changes: 84 additions & 0 deletions test/scripts/compliance-audit/stub-surface-drift.bats
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ jobs:
EOF
)

PR_AUTO_REVIEW_CANONICAL=$(cat <<'EOF'
name: PR Auto-Review — Ready Check

on:
# TODO: replace "CI" with your repository's CI workflow name(s).
workflow_run:
workflows: ["CI"]
types: [completed]
check_suite:
types: [completed]
pull_request_review:
types: [submitted, dismissed]
pull_request:
types: [opened, reopened, synchronize, ready_for_review]

permissions: {}

jobs:
pr-auto-review:
permissions:
pull-requests: read
checks: read
actions: read
uses: petry-projects/.github/.github/workflows/pr-auto-review-reusable.yml@pr-auto-review/v1-stable # NOSONAR
secrets:
GH_PAT_WORKFLOWS: ${{ secrets.GH_PAT_DON_PETRY || secrets.GH_PAT_WORKFLOWS }}
EOF
)

# ---------------------------------------------------------------------------
# AC2 — a stub that differs ONLY by its correct tier channel pin is clean on
# every guarded surface (the pin lives outside on:/permissions/concurrency).
Expand Down Expand Up @@ -187,6 +216,61 @@ EOF
[ "$status" -ne 0 ]
}

# ---------------------------------------------------------------------------
# pr-auto-review's per-repo workflow_run.workflows name is NOT trigger-surface
# drift — the template header + TODO document it as an allowed customization
# (a repo MUST name its own CI workflow), so the workflows list VALUE is
# normalized. The rest of the on: surface stays verbatim-locked (#990).
# ---------------------------------------------------------------------------

@test "pr-auto-review: renaming the workflow_run.workflows value is NOT flagged" {
local deployed="${PR_AUTO_REVIEW_CANONICAL/\[\"CI\"\]/[\"CI Pipeline\"]}"
# sanity: the workflows list really did change
[ "$deployed" != "$PR_AUTO_REVIEW_CANONICAL" ]
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 1 ]
}

@test "pr-auto-review: a multi-name workflow_run.workflows list is NOT flagged" {
local deployed="${PR_AUTO_REVIEW_CANONICAL/\[\"CI\"\]/[\"CI\", \"Lint\"]}"
# sanity: the workflows list really did change
[ "$deployed" != "$PR_AUTO_REVIEW_CANONICAL" ]
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 1 ]
}

@test "pr-auto-review: dropping the check_suite: trigger is still flagged (rest of on: stays locked)" {
local deployed
deployed=$(printf '%s\n' "$PR_AUTO_REVIEW_CANONICAL" | sed '/^ check_suite:$/,/^ types: \[completed\]$/d')
# sanity: the trigger really was removed
! grep -q '^ check_suite:$' <<< "$deployed"
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 0 ]
}

@test "pr-auto-review: removing the whole workflow_run: block is still flagged (trigger key not adjustable)" {
local deployed
deployed=$(printf '%s\n' "$PR_AUTO_REVIEW_CANONICAL" | sed '/^ workflow_run:$/,/^ types: \[completed\]$/d')
# sanity: the workflow_run trigger key really was removed
! grep -q '^ workflow_run:$' <<< "$deployed"
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 0 ]
}

@test "pr-auto-review: workflows: null is flagged (not a valid list shape)" {
local deployed="${PR_AUTO_REVIEW_CANONICAL/workflows: \[\"CI\"\]/workflows: null}"
[ "$deployed" != "$PR_AUTO_REVIEW_CANONICAL" ]
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 0 ]
}

@test "pr-auto-review: workflows: CI (bare string) is flagged (not a valid list shape)" {
local deployed="${PR_AUTO_REVIEW_CANONICAL/workflows: \[\"CI\"\]/workflows: CI}"
[ "$deployed" != "$PR_AUTO_REVIEW_CANONICAL" ]
surface_drift "$PR_AUTO_REVIEW_CANONICAL" "$deployed" "on"
[ "$status" -eq 0 ]
}

# ---------------------------------------------------------------------------
# permissions surface — added or removed permission is flagged.
# ---------------------------------------------------------------------------
Expand Down
Loading