Skip to content
Merged
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
14 changes: 14 additions & 0 deletions .github/maintainers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"schema": 1,
"repository": "integrations",
"source": "agentrust-io/.github:maintainers/roster.json",
"maintainers": [
"imran-siddique",
"pforest",
"podcastinator",
"carloshvp",
"Qiang-Xu"
],
"security_paths": [],
"security_approvals": 1
}
104 changes: 60 additions & 44 deletions .github/workflows/require-maintainer-approval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,54 +25,70 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const MAINTAINERS = ['imran-siddique', 'pforest', 'podcastinator', 'carloshvp', 'Qiang-Xu'];

const author = context.payload.pull_request.user.login;
if (MAINTAINERS.includes(author)) {
core.info(`Author ${author} is a maintainer, skipping gate`);
return;
}

// Both pull_request_target and pull_request_review payloads
// carry the PR at context.payload.pull_request.
const prNumber = context.payload.pull_request.number;

// Re-fetch the PR so we compare against the head SHA at
// evaluation time, not a possibly stale SHA from the payload.
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
owner: context.repo.owner, repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
const headSha = pr.head.sha;

// Paginate: listReviews otherwise returns only the first 30.
// Read only reviewed base-branch data. Never execute or read policy from a PR head.
let file;
try {
({ data: file } = await github.rest.repos.getContent({
owner: context.repo.owner, repo: context.repo.repo,
path: '.github/maintainers.json', ref: pr.base.sha,
}));
} catch (error) {
// One-commit bootstrap: the initial policy PR must be reviewable before its
// policy file exists on main. Missing policy on any later base fails closed.
if (error.status !== 404 || pr.base.sha !== "06c1dd113d86ae94844bcc8840b5c8c78bc62e83") throw error;
file = { encoding: 'base64', content: Buffer.from(JSON.stringify({"schema":1,"repository":"integrations","source":"agentrust-io/.github:maintainers/roster.json","maintainers":["imran-siddique","pforest","podcastinator","carloshvp","Qiang-Xu"],"security_paths":[],"security_approvals":1})).toString('base64') };
}
if (Array.isArray(file) || file.encoding !== 'base64') {
throw new Error('Missing base-branch maintainer policy');
}
const policy = JSON.parse(Buffer.from(file.content, 'base64').toString('utf8'));
if (policy.schema !== 1 || policy.repository !== context.repo.repo ||
!Array.isArray(policy.maintainers) || policy.maintainers.length < 2 ||
!policy.maintainers.every(x => typeof x === 'string' && /^[A-Za-z0-9-]+$/.test(x)) ||
new Set(policy.maintainers.map(x => x.toLowerCase())).size !== policy.maintainers.length ||
!Array.isArray(policy.security_paths) ||
!policy.security_paths.every(x => typeof x === 'string' && x.endsWith('/') && !x.startsWith('/') && !x.includes('..')) ||
policy.security_approvals !== (policy.security_paths.length ? 2 : 1)) {
throw new Error('Invalid base-branch maintainer policy');
}
const maintainers = new Set(policy.maintainers.map(x => x.toLowerCase()));
let securityChange = false;
if (policy.security_paths.length) {
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number,
});
if (files.length !== pr.changed_files) throw new Error('Incomplete changed-file inventory');
// Renaming a security file out of its directory must still require two reviews.
securityChange = files.some(f => [f.filename, f.previous_filename]
.some(p => typeof p === 'string' && policy.security_paths.some(prefix => p.startsWith(prefix))));
}
const author = pr.user.login.toLowerCase();
if (!securityChange && maintainers.has(author)) {
core.info('Maintainer-authored routine change: branch rules still require independent review.');
return;
}
const reviews = await github.paginate(github.rest.pulls.listReviews, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number,
});

// Only a maintainer's most recent non-comment review counts,
// and it must approve the current head commit. An approval of
// an older commit does not clear the gate after a later push
// (prevents approve-then-swap).
const latestByMaintainer = new Map();
for (const review of reviews) {
if (
review.user &&
review.user.type === 'User' &&
MAINTAINERS.includes(review.user.login) &&
review.state !== 'COMMENTED'
) {
latestByMaintainer.set(review.user.login, review);
const latest = new Map();
for (const review of reviews.slice().sort((a, b) =>
Date.parse(a.submitted_at || 0) - Date.parse(b.submitted_at || 0) || a.id - b.id)) {
const login = review.user?.login?.toLowerCase();
if (review.user?.type === 'User' && maintainers.has(login) &&
login !== author && review.state !== 'COMMENTED') {
latest.set(login, review);
}
}

const approved = [...latestByMaintainer.values()].some(
(r) => r.state === 'APPROVED' && r.commit_id === headSha
);

if (!approved) {
core.setFailed('Waiting for maintainer approval of the current head commit before merging.');
const approvals = [...latest.values()].filter(r =>
r.state === 'APPROVED' && r.commit_id === pr.head.sha);
const required = securityChange ? policy.security_approvals : 1;
if (approvals.length < required) {
core.setFailed('Awaiting ' + required + ' independent maintainer approval(s) of current head ' +
pr.head.sha + '; found ' + approvals.length + '. Branch rules and specification governance also apply.');
} else {
core.info(approvals.length + ' maintainer(s) approved current head ' + pr.head.sha);
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ project governance.

| Location | What belongs there | Who contributes |
|---|---|---|
| [cmcp](https://github.com/agentrust-io/cmcp), [agent-manifest](https://github.com/agentrust-io/agent-manifest), [trace-spec](https://github.com/agentrust-io/trace-spec), [trace-tests](https://github.com/agentrust-io/trace-tests) | The standard and reference implementation. Bug fixes and spec feedback welcome; no vendor product code. | Maintainers; community fixes |
| [cmcp](https://github.com/agentrust-io/cmcp), [agent-manifest](https://github.com/agentrust-io/agent-manifest), [trace-spec](https://github.com/agentrust-io/trace-spec), [TRACE conformance](https://github.com/agentrust-io/trace-spec/tree/main/conformance) | The standard and reference implementation. Bug fixes and spec feedback welcome; no vendor product code. | Maintainers; community fixes |
| [examples/](examples/) | First-party, end-to-end runnable examples, plus flagship partner examples by invitation. Every line is reviewed and every claim verified before merge. | Maintainers; invited partners |
| [integrations/](integrations/) | Your product's integration with cMCP, TRACE, or Agent Manifest: adapters, exporters, dashboards, policy packs, verifiers. Vendor-maintained. | Anyone, self-serve |
| [awesome-ai-governance](https://github.com/agentrust-io/awesome-ai-governance) | Neutral listings of notable agent-governance tools, including ones that do not integrate with this stack. | Anyone meeting the listing criteria |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,14 @@ Business-boundary refusal, retry, and concurrency cases are in

## Released sources and nonclaims

- [UCP v2026-08-25 Checkout schema](https://github.com/Universal-Commerce-Protocol/ucp/blob/v2026-08-25/source/schemas/shopping/checkout.json),
[REST binding](https://github.com/Universal-Commerce-Protocol/ucp/blob/v2026-08-25/docs/specification/shopping/checkout/rest.md),
and [HTTP signatures](https://github.com/Universal-Commerce-Protocol/ucp/blob/v2026-08-25/docs/specification/signatures.md).
- [UCP v2026-08-25 Checkout schema](https://raw.githubusercontent.com/Universal-Commerce-Protocol/ucp/v2026-08-25/source/schemas/shopping/checkout.json),
[REST binding](https://raw.githubusercontent.com/Universal-Commerce-Protocol/ucp/v2026-08-25/docs/specification/shopping/checkout/rest.md),
and [HTTP signatures](https://raw.githubusercontent.com/Universal-Commerce-Protocol/ucp/v2026-08-25/docs/specification/signatures.md).
- [Official UCP Python SDK release](https://github.com/Universal-Commerce-Protocol/python-sdk/releases/tag/v2026-08-25),
installed as `ucp-sdk==0.5.0`; JSON Schema validation complements its models.
- [http-message-signatures v2.0.1](https://github.com/pyauth/http-message-signatures/tree/v2.0.1),
[joserfc 1.7.5](https://pypi.org/project/joserfc/1.7.5/), and
[TRACE v0.10.0 signing/verification](https://github.com/agentrust-io/trace-spec/blob/v0.10.0/src/agentrust_trace/sign.py).
[TRACE v0.10.0 signing/verification](https://raw.githubusercontent.com/agentrust-io/trace-spec/v0.10.0/src/agentrust_trace/sign.py).

This demonstrates application-level accountability under configured local keys
and policy. It does **not** establish real merchant identity, buyer consent,
Expand Down
2 changes: 1 addition & 1 deletion examples/ca2a-delegation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The other examples in this repo govern the **agent-to-tool** boundary: cMCP deci

It uses the credit-risk workflow from [`financial-services/`](../financial-services/README.md) as the worked case, and maps the same pattern onto the other examples at the bottom.

> **Scope of what runs here.** cA2A is in alpha. This example exercises the part that is built today: **attenuated delegation credentials and offline chain verification** (`ca2a_runtime.delegation`). The live peer path (attesting an inbound peer, sealing the payload to its measurement) and the per-hop TRACE provenance record are cA2A roadmap. See the [cA2A ROADMAP](https://github.com/agentrust-io/ca2a/blob/main/ROADMAP.md) and [LIMITATIONS](https://github.com/agentrust-io/ca2a/blob/main/LIMITATIONS.md).
> **Scope of what runs here.** cA2A is in alpha. This example exercises the part that is built today: **attenuated delegation credentials and offline chain verification** (`ca2a_runtime.delegation`). The live peer path (attesting an inbound peer, sealing the payload to its measurement) and the per-hop TRACE provenance record are cA2A roadmap. See the [cA2A ROADMAP](https://raw.githubusercontent.com/agentrust-io/ca2a/main/ROADMAP.md) and [LIMITATIONS](https://raw.githubusercontent.com/agentrust-io/ca2a/main/LIMITATIONS.md).

---

Expand Down
2 changes: 1 addition & 1 deletion integrations/docker-sandbox-kit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ credentials, volumes, ports. This adapter takes a published Kit's platform
manifest and builds a TRACE Level 0 Trust Record whose `policy.bundle_hash` is
the digest of that descriptor, byte for byte as the frontend published it.

Written against [SPEC-v3](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md)
Written against [SPEC-v3](https://raw.githubusercontent.com/docker/sandbox-kit-spec/main/docs/spec/SPEC-v3.md)
at commit `31791ea` (2026-10-01).

## Run it
Expand Down
Loading