Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/reference-implementation-supply-chain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Runs the AGT supply-chain checks that nothing else invokes.
#
# verify-pin.sh clones agt.lock's pinned commit and byte-diffs the vendored .rego
# files against it. A mismatch fails the job. It skips the other files in policy/lib,
# including data.json, which holds the egress allowlist.
#
# run-upstream-watch.sh diffs AGT's contract surfaces between the pinned commit and
# upstream main, and prints a report. Drift exits 0 because moving the pin is a human
# call. The job fails only when the watch could not run. The report goes to the job
# summary.
#
# verify:zero-diff is left out. It compares against a branch that does not exist in
# this repository and exits 1 by design here.
#
# Both scripts clone from GitHub, so this is its own workflow. The test job in
# reference-implementation.yml should not depend on the network.
#
# No workflow expression appears inside a `run:` block.
name: Reference implementation supply chain

on:
pull_request:
paths:
- "reference-implementations/agt/agt.lock"
- "reference-implementations/agt/policy/**"
- "reference-implementations/agt/scripts/verify-pin.sh"
- "reference-implementations/agt/scripts/run-upstream-watch.sh"
- ".github/workflows/reference-implementation-supply-chain.yml"
push:
branches: ["main", "integration"]
paths:
- "reference-implementations/agt/agt.lock"
- "reference-implementations/agt/policy/**"
- "reference-implementations/agt/scripts/verify-pin.sh"
- "reference-implementations/agt/scripts/run-upstream-watch.sh"
- ".github/workflows/reference-implementation-supply-chain.yml"
schedule:
# Weekly, an hour after zizmor. Upstream moves whether or not this tree changes.
- cron: "0 7 * * 1"
workflow_dispatch:

permissions: {}

concurrency:
group: reference-implementation-supply-chain-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
agt-supply-chain:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
defaults:
run:
working-directory: reference-implementations/agt
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# agt.lock comes from the pull request, and both scripts clone whatever agt_repo
# names. The expected value lives here because /.github/ needs a project lead's
# review. This checks the repository only. agt_ref still comes from the pull
# request, so a reviewer has to read every change to it.
- name: Check that agt.lock names the upstream repository
run: |
set -euo pipefail
expected="https://github.com/microsoft/agent-governance-toolkit"
actual="$(jq -r '.agt_repo' agt.lock)"
if [ "$actual" != "$expected" ]; then
echo "agt.lock names $actual, expected $expected" >&2
exit 1
fi

# Same pin as reference-implementation.yml.
- name: Install Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2
with:
bun-version: "1.3.11"

- name: Install dependencies from the lockfile
run: bun install --frozen-lockfile

# Both scripts clean up with `trash` and refuse to start without it. Same pin
# as reference-implementation.yml.
- name: Install the trash CLI the scripts require
run: bun add --global trash-cli@7.2.0

- name: Verify the vendored bundle against the pinned commit
run: bash scripts/verify-pin.sh

# pipefail so a failed watch fails the step instead of tee's exit status.
- name: Report drift against upstream main
run: |
set -euo pipefail
bash scripts/run-upstream-watch.sh | tee -a "$GITHUB_STEP_SUMMARY"
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bun run watch:upstream

This runs `scripts/run-upstream-watch.sh`, which clones AGT twice, once at the pinned commit and once at `main`, and hands the two paths to the runner as `PINNED_AGT_CLONE` and `UPSTREAM_AGT_CLONE`. The runner diffs AGT's eight declared contract surfaces field by field, validates the Guardian's policy input against both schema versions, and reports which tools the two hookmaps declare against the manifest's registry.

The watch reports. It never fails a build. Nothing reaches this tree until a human moves the pin in `agt.lock`.
The watch reports drift, and drift never fails a build. A run that could not finish does fail the job. Nothing reaches this tree until a human moves the pin in `agt.lock`.

## Use it in-process

Expand Down
Loading