diff --git a/.github/scripts/tests/agent-ingress-workflow.bats b/.github/scripts/tests/agent-ingress-workflow.bats index 9667ef32..0fe4dd6c 100644 --- a/.github/scripts/tests/agent-ingress-workflow.bats +++ b/.github/scripts/tests/agent-ingress-workflow.bats @@ -101,7 +101,7 @@ ROLES=(dev-lead pr-auto-review pr-review pr-review-mention ci-failure-analyst) [[ "$output" == *"/pr-review-mention-reusable.yml@pr-review-mention/v2-stable" ]] run yq '.jobs.ci-failure-analyst.uses' "$WORKFLOW" [ "$status" -eq 0 ] - [[ "$output" == *"/ci-failure-analyst-reusable.yml@b58510275dd1cbbd13c0733c15265d51fd63b992" ]] + [[ "$output" == *"/ci-failure-analyst-reusable.yml@ci-failure-analyst/v1-stable" ]] } @test "dev-lead job keeps the base=main PR filter and declares no caller concurrency" { @@ -149,7 +149,7 @@ ROLES=(dev-lead pr-auto-review pr-review pr-review-mention ci-failure-analyst) run yq '.jobs.ci-failure-analyst.if' "$WORKFLOW" [[ "$output" == *"github.event_name == 'check_run'"* ]] [[ "$output" == *"github.event.check_run.conclusion == 'failure'"* ]] - [[ "$output" == *"!startsWith(github.event.check_run.name, 'CI Failure Analyst')"* ]] + [[ "$output" == *"!startsWith(github.event.check_run.name, 'ci-failure-analyst')"* ]] } @test "if: guards never read repo state (vars/secrets/needs/hashFiles)" { @@ -168,3 +168,23 @@ ROLES=(dev-lead pr-auto-review pr-review pr-review-mention ci-failure-analyst) [[ "$output" =~ @pr-review/v1-stable[[:space:]]+#[[:space:]]*NOSONAR\(githubactions:S7637\)[[:space:]]+first-party[[:space:]]+channel[[:space:]]+ref ]] [[ "$output" != *"DEFECTIVE PIN"* ]] } + +@test "ci-failure-analyst loop guard matches the analyst's own check run name (#2175)" { + # A reusable-workflow job's check run is named ' / ', + # so the analyst's own check is 'ci-failure-analyst / analyze'. The guard must + # match that prefix, or a failed analyst run re-triggers the analyst. + run yq '.jobs.ci-failure-analyst.if' "$WORKFLOW" + [ "$status" -eq 0 ] + local prefix + prefix="$(printf '%s' "$output" | sed -n "s/.*!startsWith(github.event.check_run.name, '\([^']*\)').*/\1/p")" + [ -n "$prefix" ] + # The reusable's job id is 'analyze' (ci-failure-analyst-reusable.yml). + [[ 'ci-failure-analyst / analyze' == "$prefix"* ]] +} + +@test "ci-failure-analyst pins its channel, not a bare SHA (#2176)" { + run grep -E '/ci-failure-analyst-reusable\.yml@' "$WORKFLOW" + [ "$status" -eq 0 ] + [[ "$output" =~ @ci-failure-analyst/v1-stable[[:space:]]+#[[:space:]]*NOSONAR\(githubactions:S7637\)[[:space:]]+first-party[[:space:]]+channel[[:space:]]+ref ]] + [[ "$output" != *"DEFECTIVE PIN"* ]] +} diff --git a/.github/workflows/agent-ingress.yml b/.github/workflows/agent-ingress.yml index d411cff0..a0c97e13 100644 --- a/.github/workflows/agent-ingress.yml +++ b/.github/workflows/agent-ingress.yml @@ -169,7 +169,7 @@ jobs: if: >- github.event_name == 'check_run' && github.event.check_run.conclusion == 'failure' - && !startsWith(github.event.check_run.name, 'CI Failure Analyst') + && !startsWith(github.event.check_run.name, 'ci-failure-analyst') concurrency: group: "ci-failure-analyst-${{ github.event.check_run.head_sha }}" cancel-in-progress: false @@ -179,6 +179,6 @@ jobs: actions: read contents: read checks: read - uses: petry-projects/.github-private/.github/workflows/ci-failure-analyst-reusable.yml@b58510275dd1cbbd13c0733c15265d51fd63b992 # DEFECTIVE PIN — bare SHA, see §5 + uses: petry-projects/.github-private/.github/workflows/ci-failure-analyst-reusable.yml@ci-failure-analyst/v1-stable # NOSONAR(githubactions:S7637) first-party channel ref secrets: CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}