Merge pull request #2428 from ai-agent-assembly/v0.0.1/AAASM-6089/fix… #1206
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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." |