Skip to content

Merge pull request #2428 from ai-agent-assembly/v0.0.1/AAASM-6089/fix… #1206

Merge pull request #2428 from ai-agent-assembly/v0.0.1/AAASM-6089/fix…

Merge pull request #2428 from ai-agent-assembly/v0.0.1/AAASM-6089/fix… #1206

name: Contact Metadata Drift Check
# AAASM-5520: the security reporting address and shared response-target SLAs in
# SECURITY.md and README.md are owned by the canonical org metadata registry in
# ai-agent-assembly/.github (ADR 0014 / AAASM-5519).
# scripts/check_contact_metadata.py syncs/audits them against the pinned
# canonical facts. This gate fails closed if either drifts, so a stale contact
# literal can never merge. Repo-specific security prose is untouched.
on:
pull_request:
# AAASM-5677: deliberately NOT path-filtered — selection moved to the
# `changes` router below. This gate is governance-bearing (CONTRIBUTING,
# "Which CI checks are governance-bearing"): its failure means a published
# statement about how to reach us for a vulnerability is false, and nothing
# else in the tree reads those literals. It therefore has to be a required
# status check, and a required check only works if it reliably reports —
# a path-filtered workflow that does not trigger produces no check run at
# all, and a required check that never arrives blocks the PR forever.
push:
branches:
- main
# AAASM-5677: lets `ci.yml` invoke this workflow's jobs directly, so the
# `ci-success` aggregate can genuinely `needs:` its conclusion instead of
# merely running alongside it unobserved.
workflow_call:
# AAASM-5677: a literal group name, not `${{ github.workflow }}-${{ github.ref }}`.
# Under `workflow_call`, `github.workflow` resolves to the CALLING workflow's
# name ("CI"), which every other governance workflow this ticket adds
# `workflow_call` to would also compute — five satellites racing for one
# concurrency group inside the same `ci.yml` run, `cancel-in-progress: true`
# would cancel siblings, not supersede stale runs of this workflow.
#
# `github.event_name` is appended for the same reason: this workflow's own
# `pull_request` trigger and ci.yml's `workflow_call` invocation both run on
# the same PR at the same time, and without this the two would ALSO collide
# under this group — see capability-manifest.yml's identical comment for the
# live failure (PR #2087) this pattern produced there.
#
# `cancel-in-progress: false`, changed from the original `true` for the same
# reason as capability-manifest.yml's identical change: a known GitHub
# Actions race where two runs entering the same concurrency group in quick
# succession don't always cancel deterministically, observed live on the same
# PR. This job is fast, so the cost of an occasional stale run finishing
# anyway is negligible next to a spuriously red check.
concurrency:
group: contact-metadata-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: false
permissions:
contents: read
jobs:
# AAASM-5677: consulted for `pull_request` only. The `push` backstop stays
# unconditional so the gate still runs on the merge that breaks it.
changes:
name: Detect changed areas (Contact Metadata)
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
outputs:
contact: ${{ steps.filter.outputs.contact }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
id: filter
with:
filters: |
contact:
- 'SECURITY.md'
- 'README.md'
- 'scripts/check_contact_metadata.py'
- '.github/workflows/contact-metadata-check.yml'
contact-drift:
name: contact metadata drift
needs: [changes]
# `!cancelled()` stops a skipped `changes` (every non-PR event) from
# force-skipping this job. A failed `changes` leaves the condition false,
# so this skips and the aggregate below turns red: fail closed.
if: >-
!cancelled() &&
(github.event_name != 'pull_request' || needs.changes.outputs.contact == 'true')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Audit contact literals against the pinned registry
run: python scripts/check_contact_metadata.py --check
# AAASM-5677: the stable required context. Named separately from the job it
# aggregates so renaming an internal job cannot silently drop the branch
# protection requirement.
contact-metadata-success:
name: Contact Metadata Success
needs: [changes, contact-drift]
if: always()
runs-on: ubuntu-latest
steps:
- name: Verify no required job failed or was cancelled
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: |
echo "Job results: $RESULTS"
for r in $RESULTS; do
case "$r" in
failure|cancelled)
echo "::error::A required Contact Metadata job concluded with '$r'"
exit 1
;;
esac
done
echo "All required Contact Metadata jobs passed or were intentionally skipped."