Skip to content

chore(deps): bump OMT-Global/bootstrap/.github/workflows/release-preflight-reusable.yml from bc67f149f35c5ca8f0eb14a8ef9ad578c66bf6e2 to 848846fc40b02c512e2b86d23bb1b295f7908f8a #540

chore(deps): bump OMT-Global/bootstrap/.github/workflows/release-preflight-reusable.yml from bc67f149f35c5ca8f0eb14a8ef9ad578c66bf6e2 to 848846fc40b02c512e2b86d23bb1b295f7908f8a

chore(deps): bump OMT-Global/bootstrap/.github/workflows/release-preflight-reusable.yml from bc67f149f35c5ca8f0eb14a8ef9ad578c66bf6e2 to 848846fc40b02c512e2b86d23bb1b295f7908f8a #540

Workflow file for this run

name: PR Fast CI
on:
pull_request:
types: [opened, edited, synchronize, reopened, ready_for_review]
pull_request_review:
types: [submitted, edited, dismissed]
concurrency:
group: pr-fast-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read
env:
NODE_VERSION: '20'
PYTHON_VERSION: '3.12'
defaults:
run:
shell: bash
jobs:
changes:
name: Detect Relevant Changes
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
outputs:
app: ${{ steps.filter.outputs.app }}
ci: ${{ steps.filter.outputs.ci }}
steps:
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4
id: filter
with:
filters: |
app:
- 'project.bootstrap.yaml'
- 'AGENTS.md'
- 'CONTRIBUTING.md'
- '.github/PULL_REQUEST_TEMPLATE.md'
- '.githooks/**'
- '.github/workflows/**'
- 'scripts/**'
- 'docs/bootstrap/**'
- 'README.md'
- 'docs/**'
ci:
- 'project.bootstrap.yaml'
- 'AGENTS.md'
- 'CONTRIBUTING.md'
- '.github/PULL_REQUEST_TEMPLATE.md'
- '.githooks/**'
- '.github/workflows/**'
- 'scripts/**'
- 'docs/bootstrap/**'
- '.env.example'
- 'CODEOWNERS'
fast-checks:
name: Fast Checks
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 15
needs: changes
if: >-
github.event.pull_request.draft == false &&
(needs.changes.outputs.app == 'true' || needs.changes.outputs.ci == 'true')
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run fast checks
run: bash scripts/ci/run-fast-checks.sh
verify-dependabot-commits:
name: Verify Dependabot-only Commits
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 5
if: github.event.pull_request.draft == false
outputs:
bot_only: ${{ steps.verify.outputs.bot_only }}
env:
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_COMMITS_URL: ${{ github.event.pull_request.commits_url }}
PR_BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_TOKEN: ${{ github.token }}
steps:
- id: verify
name: Require Dependabot commits or verified main merges
run: |
set -euo pipefail
page=1
commits_seen=0
bot_only=false
merge_tree_repo="$(mktemp -d)"
trap 'rm -rf "$merge_tree_repo"' EXIT
git -C "$merge_tree_repo" init -q
git -C "$merge_tree_repo" remote add origin "https://github.com/$PR_BASE_REPO.git"
git_auth="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')"
git -C "$merge_tree_repo" config http.extraheader "Authorization: Basic $git_auth"
git -C "$merge_tree_repo" fetch --no-tags origin "$PR_BASE_SHA" >/dev/null 2>&1
base_first_parent_contains() {
git -C "$merge_tree_repo" rev-list --first-parent "$PR_BASE_SHA" | grep -F -x "$1" >/dev/null
}
verify_merge_tree() {
local merge_commit="$1"
local first_parent="$2"
local second_parent="$3"
git -C "$merge_tree_repo" fetch --no-tags origin "$merge_commit" "$first_parent" "$second_parent" >/dev/null 2>&1 || return 1
local actual_tree
local expected_tree
actual_tree="$(git -C "$merge_tree_repo" rev-parse "$merge_commit^{tree}")" || return 1
[[ -n "$actual_tree" ]] || return 1
expected_tree="$(git -C "$merge_tree_repo" merge-tree --write-tree "$first_parent" "$second_parent" 2>/dev/null)" || return 1
[[ -n "$expected_tree" ]] || return 1
[[ "$actual_tree" == "$expected_tree" ]]
}
if [[ "$PR_AUTHOR" == "dependabot[bot]" ]]; then
bot_only=true
previous_commit=""
while :; do
response="$(curl --fail-with-body --silent --show-error --location --header "Authorization: Bearer $GITHUB_TOKEN" --header "Accept: application/vnd.github+json" "$PR_COMMITS_URL?per_page=100&page=$page")"
jq -e 'type == "array"' <<<"$response" >/dev/null
count="$(jq 'length' <<<"$response")"
[[ "$count" -gt 0 ]] || break
commits_seen=$((commits_seen + count))
while IFS= read -r commit; do
commit_sha="$(jq -r '.sha' <<<"$commit")"
first_parent="$(jq -r '.parents[0].sha' <<<"$commit")"
if jq -e '(.committer != null and .committer.login == "web-flow" and .commit.verification.verified == true and .commit.verification.reason == "valid" and .author != null and .author.login == "dependabot[bot]")' <<<"$commit" >/dev/null; then
valid_commit=false
if [[ "$(jq '.parents | length' <<<"$commit")" == 1 ]] && { [[ -z "$previous_commit" ]] && base_first_parent_contains "$first_parent" || [[ "$first_parent" == "$previous_commit" ]]; }; then
valid_commit=true
fi
elif jq -e '(.committer != null and .committer.login == "web-flow" and .commit.verification.verified == true and .commit.verification.reason == "valid" and .author != null and .author.type == "User" and (.parents | length) == 2 and ((.commit.message // "") | test("^Merge branch.*main.*into dependabot/")))' <<<"$commit" >/dev/null; then
second_parent="$(jq -r '.parents[1].sha' <<<"$commit")"
valid_commit=false
if { [[ -z "$previous_commit" ]] && base_first_parent_contains "$first_parent" || [[ "$first_parent" == "$previous_commit" ]]; } && base_first_parent_contains "$second_parent" && verify_merge_tree "$commit_sha" "$first_parent" "$second_parent"; then
valid_commit=true
fi
else
valid_commit=false
fi
if [[ "$valid_commit" != true ]]; then
bot_only=false
fi
previous_commit="$commit_sha"
done < <(jq -c '.[]' <<<"$response")
[[ "$count" -lt 100 ]] && break
page=$((page + 1))
done
[[ "$commits_seen" -gt 0 ]] || bot_only=false
fi
echo "Verified $commits_seen PR commit(s); Dependabot-only=$bot_only"
echo "bot_only=$bot_only" >> "$GITHUB_OUTPUT"
validate-pr-description:
name: Validate PR Description
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 5
if: github.event.pull_request.draft == false && needs.verify-dependabot-commits.outputs.bot_only != 'true'
needs: verify-dependabot-commits
env:
PR_BODY: ${{ github.event.pull_request.body }}
steps:
- name: Require generated PR template content
run: |
failed=0
require_line() {
local line="$1"
if ! grep -Fqx "$line" <<<"$PR_BODY"; then
echo "Missing required PR section: $line"
failed=1
fi
}
require_line "## Summary"
require_line "## Governing Issue"
require_line "## Validation"
require_line "## Bootstrap Governance"
require_line "## Merge Automation"
require_line "## Notes"
if grep -Eiq 'Closes #$|#<issue-number>|what changed|why it changed|notable tradeoffs|migration or rollout notes|follow-up work if any' <<<"$PR_BODY"; then
echo "PR body still contains template placeholder text."
failed=1
fi
if ! grep -Eiq '(^|[[:space:]-])(((close[sd]?|fix(e[sd])?|resolve[sd]?|refs?|part[[:space:]]+of)[[:space:]]+)?(#|[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+#|https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+/issues/)[0-9]+|no issue is linked|no linked issue|without a linked issue|no governing issue)' <<<"$PR_BODY"; then
echo "PR body must close/link an issue or explicitly explain why no issue is linked."
failed=1
fi
if ! grep -Eiq '(^|[[:space:]-])(\[[xX]\]|not run|not applicable|n/a)' <<<"$PR_BODY"; then
echo "PR body must include validation evidence, a checked validation item, or a reason validation was not run."
failed=1
fi
auto_merge_evidence="$(grep -Eiv '^[[:space:]]*-[[:space:]]+\[[[:space:]]\][[:space:]]' <<<"$PR_BODY" || true)"
if ! grep -Eiq 'auto-merge (is )?(enabled|armed)|enabled auto-merge|gh pr merge --auto|auto_merge|auto merge enabled|auto-merge (is )?(unavailable|unsafe|not available|not safe)|plan-limit|fallback merge-readiness' <<<"$auto_merge_evidence"; then
echo "PR body must state that the PR author enabled auto-merge, or explain why auto-merge is unavailable/unsafe."
failed=1
fi
exit "$failed"
validate-secrets:
name: Validate Secrets
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 10
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Scan repository for secret patterns
run: bash scripts/check-detect-secrets.sh --all-files
validate-pr-governance:
name: Validate PR Governance
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 5
if: github.event.pull_request.draft == false && needs.verify-dependabot-commits.outputs.bot_only != 'true'
needs: verify-dependabot-commits
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_CREATED_AT: ${{ github.event.pull_request.created_at }}
PR_GOVERNANCE_ENFORCE_AFTER: '2026-07-13T23:00:00Z'
PR_FILES_URL: ${{ github.event.pull_request.url }}/files
PR_COMMITS_URL: ${{ github.event.pull_request.commits_url }}
PR_REVIEWS_URL: ${{ github.event.pull_request.url }}/reviews
GITHUB_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Validate title, DCO, size, ADR, and reviewer evidence
run: bash scripts/ci/check-pr-governance.sh
validate-action-pins:
name: Validate Action Pins
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
timeout-minutes: 5
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Require immutable third-party action pins
run: bash scripts/ci/check-action-pins.sh
ci-gate:
name: CI Gate
runs-on: ['self-hosted', 'linux', 'shell-only', 'public']
if: always()
needs:
- changes
- fast-checks
- verify-dependabot-commits
- validate-pr-description
- validate-secrets
- validate-pr-governance
- validate-action-pins
steps:
- name: Check required PR jobs
env:
RESULTS: >-
changes=${{ needs.changes.result }}
fast-checks=${{ needs.fast-checks.result }}
verify-dependabot-commits=${{ needs.verify-dependabot-commits.result }}
validate-pr-description=${{ needs.validate-pr-description.result }}
validate-secrets=${{ needs.validate-secrets.result }}
validate-pr-governance=${{ needs.validate-pr-governance.result }}
validate-action-pins=${{ needs.validate-action-pins.result }}
run: |
failed=0
for entry in $RESULTS; do
job="${entry%%=*}"
status="${entry##*=}"
if [[ "$status" == "success" || "$status" == "skipped" ]]; then
echo "OK $job => $status"
else
echo "FAIL $job => $status"
failed=1
fi
done
exit "$failed"