mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 13:10:13 +00:00
8d24c5680b
.github/scripts/Get-Endpoints.ps1 defines the storage account (blob and table derived from its name), the containers, the AdminConfiguration row, the legacy mirror, the download alias, API, MCP, portal, www, docs and the timestamp server. Workflows load it once per job; the script publisher and the local release build call it; the dev-render anchors are built from the alias entry. deploy-web takes NEXT_PUBLIC_API_BASE_URL and NEXT_PUBLIC_PLATFORM_STATS_MANIFEST_URL from the registry instead of repository variables and refuses an empty value. A new Workflow gates job fails on any host spelled out in a workflow or CI helper; the enforced list is derived from the registry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
126 lines
6.2 KiB
YAML
126 lines
6.2 KiB
YAML
name: Workflow gates
|
|
|
|
# Three checks over the workflow files and their helper scripts:
|
|
# * verify-pins -- every third-party action is referenced by a full commit SHA plus a
|
|
# version comment (stricter than zizmor's unpinned-uses audit).
|
|
# * zizmor -- static analysis of every workflow (permissions, credential
|
|
# persistence, template injection, ...). Configuration and the
|
|
# reasoned ignores live in zizmor.yml at the repository root; the
|
|
# same run is expected locally before a workflow change is committed.
|
|
# * hosts -- no workflow or .github/scripts helper spells out a host; every one
|
|
# comes from .github/scripts/Get-Endpoints.ps1, CI's member of the URL
|
|
# registry (the C#, web and MCP registries have guard tests of their own).
|
|
#
|
|
# Every third-party action must be referenced by a full commit SHA, never by a tag.
|
|
# Tags are mutable: whoever controls an action repository can repoint v4 at new code,
|
|
# and that code runs inside jobs that hold the code-signing identity, the storage
|
|
# credentials and a token that can push to main. A SHA is the only reference an
|
|
# upstream owner cannot change under us.
|
|
#
|
|
# Lives in its own workflow rather than in ci.yml: CI deliberately ignores changes to
|
|
# the other workflow files, so a guard placed there would stay silent for exactly the
|
|
# commits it needs to inspect. Dependabot's action-pin PRs are the main customer: they
|
|
# rewrite workflow files without anyone running zizmor locally.
|
|
#
|
|
# Like CI, this reports rather than blocks: main is deliberately unprotected, so a red
|
|
# run is a signal to act on, not a merge barrier. Making it binding means adding
|
|
# 'Verify action pins' as a required status check -- a branch-protection decision, not
|
|
# something this file can assert.
|
|
#
|
|
# The pins are not maintained by hand — .github/dependabot.yml opens a monthly grouped
|
|
# PR that rewrites both the SHA and the trailing version comment. The comment is
|
|
# therefore required too: it is what makes a pinned line reviewable. It names the exact
|
|
# release tag (# v7.0.1), never the floating major (# v7): a major tag moves with every
|
|
# upstream release, after which the comment no longer names the pinned commit and
|
|
# zizmor's ref-version-mismatch flags every line that carries it.
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths: ['.github/workflows/**', '.github/scripts/**', '.github/dependabot.yml', 'zizmor.yml']
|
|
pull_request:
|
|
branches: [main]
|
|
paths: ['.github/workflows/**', '.github/scripts/**', '.github/dependabot.yml', 'zizmor.yml']
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
verify-pins:
|
|
name: Verify action pins
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Every third-party action is pinned to a SHA
|
|
run: |
|
|
set -uo pipefail
|
|
failed=0
|
|
while IFS=: read -r file line ref; do
|
|
# Reusable workflows from this repository (workspace-relative ./ or the
|
|
# self-repository form $/) move with the commit that calls them, so there is
|
|
# nothing to pin.
|
|
case "$ref" in ./*|\$/*) continue ;; esac
|
|
|
|
if [[ "$ref" =~ ^[^@]+@[0-9a-f]{40}[[:space:]]+#[[:space:]]*v?[0-9]+\.[0-9]+\.[0-9]+([[:space:]]|$) ]]; then
|
|
printf 'ok %s:%s %s\n' "$file" "$line" "$ref"
|
|
continue
|
|
fi
|
|
|
|
if [[ "$ref" =~ ^[^@]+@[0-9a-f]{40}[[:space:]]*$ ]]; then
|
|
echo "::error file=$file,line=$line::Pinned but the version comment is missing: '$ref'. Write 'owner/action@<sha> # vX.Y.Z' so the line stays reviewable."
|
|
elif [[ "$ref" =~ ^[^@]+@[0-9a-f]{40}[[:space:]]+# ]]; then
|
|
echo "::error file=$file,line=$line::The version comment must name the exact release tag the SHA resolves to ('# vX.Y.Z'), not a floating major: '$ref'. Find it with: gh api repos/<owner>/<action>/git/matching-refs/tags/vN"
|
|
else
|
|
echo "::error file=$file,line=$line::Action '$ref' is not pinned to a commit SHA. Tags are mutable -- resolve it with: gh api repos/<owner>/<action>/git/ref/tags/<tag>"
|
|
fi
|
|
failed=1
|
|
# -H is load-bearing: with a single matching file grep omits the name, the
|
|
# fields shift by one and every diagnostic points at nothing.
|
|
done < <(grep -nHE '^[[:space:]]*(-[[:space:]]+)?uses:' .github/workflows/*.yml \
|
|
| sed -E 's/^([^:]+):([0-9]+):[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]*/\1:\2:/')
|
|
|
|
if [ "$failed" -ne 0 ]; then
|
|
echo "::error::Unpinned action references found -- fix them before this reaches main."
|
|
exit 1
|
|
fi
|
|
echo "All action references are pinned to commit SHAs."
|
|
|
|
zizmor:
|
|
name: zizmor audit
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
security-events: write # SARIF upload: findings land in the Code scanning tab next to CodeQL
|
|
actions: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# zizmor itself is version-pinned like every other tool here; bump it together with
|
|
# the local install so the gate and the pre-commit run agree on the finding set.
|
|
# Informational findings (template expansion of our own step outputs in pwsh) are
|
|
# visible locally but do not fail the gate.
|
|
- uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
|
|
with:
|
|
version: 1.30.1
|
|
min-severity: low
|
|
|
|
hosts:
|
|
name: Hosts only from the endpoint registry
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# The enforced host list is derived from the registry itself, plus every Azure storage,
|
|
# App Service and autopilotmonitor.com host, so it cannot fall behind a new entry.
|
|
- name: No host literal outside .github/scripts/Get-Endpoints.ps1
|
|
shell: pwsh
|
|
run: ./.github/scripts/Assert-HostsFromRegistry.ps1
|