diff --git a/tests/persona_mention.bats b/tests/persona_mention.bats index 207896358..98407e318 100644 --- a/tests/persona_mention.bats +++ b/tests/persona_mention.bats @@ -863,3 +863,159 @@ runtime: [ "$status" -eq 0 ] [ "$output" = "skip below-floor" ] } + +# --- workflow job-level if: pre-filters (#1288) ---------------------------- +# jobs.route.if and jobs.route-pull-request.if decide whether a run ever reaches +# a step holding the org token. Each restates, in expression syntax, a shell +# pre-filter tested above (pm_should_route / pm_pr_should_route), so the two +# copies can drift. These tests parse the workflow (python3 + PyYAML, already +# required by pm_manifest_query) and pin the expressions clause by clause — not +# the file's text, so a matching string in a YAML comment cannot satisfy them. + +WORKFLOW="$SCRIPT_DIR/.github/workflows/persona-mention-reusable.yml" + +# job_if — the job's raw if: expression, as parsed from the workflow. +job_if() { + python3 - "$WORKFLOW" "$1" <<'PY' +import sys, yaml +with open(sys.argv[1]) as f: + print(yaml.safe_load(f)["jobs"][sys.argv[2]]["if"]) +PY +} + +# job_if_clauses — the if: split on '&&', one whitespace-normalised clause +# per line. Asserting on whole clauses means a negated or wrapped copy of an +# expected clause (e.g. '!contains(...)' for 'contains(...)') does not match. +job_if_clauses() { + python3 - "$WORKFLOW" "$1" <<'PY' +import sys, yaml +with open(sys.argv[1]) as f: + expr = yaml.safe_load(f)["jobs"][sys.argv[2]]["if"] +for clause in expr.split("&&"): + print(" ".join(clause.split())) +PY +} + +# has_clause — 0 if is one of exactly. +has_clause() { + grep -Fxq -- "$2" <<<"$1" +} + +# bot_logins_compared — the sorted logins excluded by +# " != ''" clauses. +bot_logins_compared() { + local clause lhs="$2" pattern="^([^[:space:]]+) != '([^']+)'$" + while IFS= read -r clause; do + if [[ "$clause" =~ $pattern ]] && [ "${BASH_REMATCH[1]}" = "$lhs" ]; then + printf '%s\n' "${BASH_REMATCH[2]}" + fi + done <<<"$1" | sort -u +} + +TRUST_FLOOR_CLAUSE_COMMENT="contains(fromJSON('[\"OWNER\",\"MEMBER\",\"COLLABORATOR\"]'), github.event.comment.author_association)" +TRUST_FLOOR_CLAUSE_PR="contains(fromJSON('[\"OWNER\",\"MEMBER\",\"COLLABORATOR\"]'), github.event.pull_request.author_association)" + +@test "route.if is a pure && conjunction (no || can bypass a guard)" { + run job_if route + [ "$status" -eq 0 ] + [[ "$output" != *"||"* ]] +} + +@test "route.if keeps the comment recursion guard: marker matched ANYWHERE (!contains, #860)" { + local clauses + clauses="$(job_if_clauses route)" + has_clause "$clauses" "!contains(github.event.comment.body, '` marker is unchanged.' + run pm_pr_should_route don-petry don-petry OWNER "$quoted" + [ "$status" -eq 0 ] + has_clause "$clauses" "!startsWith(github.event.pull_request.body, '