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
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
.github/workflows/ @agentrust-io/maintainers @lywinged @rajnisht7

# Conformance suite retains its existing maintainer review ownership.
/conformance/ @agentrust-io/maintainers
/.github/workflows/conformance-*.yml @agentrust-io/maintainers
/conformance/ @agentrust-io/maintainers @lywinged @rajnisht7
/.github/workflows/conformance-*.yml @agentrust-io/maintainers @lywinged @rajnisht7
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": "trace-spec",
"source": "agentrust-io/.github:maintainers/roster.json",
"maintainers": [
"imran-siddique",
"lywinged",
"pforest",
"Qiang-Xu",
"rajnisht7"
],
"security_paths": [],
"security_approvals": 1
}
1 change: 1 addition & 0 deletions .github/workflows/conformance-package.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Conformance package build

on:
workflow_call:
workflow_dispatch:
pull_request:
paths:
Expand Down
69 changes: 69 additions & 0 deletions .github/workflows/conformance-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Conformance publisher

on:
release:
types: [published]
workflow_dispatch:
inputs:
target:
description: Build only, or publish to a verified TestPyPI publisher
type: choice
options: [build, testpypi]
default: build

permissions:
contents: read

jobs:
build:
if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'conformance-v')
uses: ./.github/workflows/conformance-package.yml
tag:
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, 'conformance-v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Match conformance tag to package version
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
python - <<'PY'
import os, tomllib
from pathlib import Path
version = tomllib.loads(Path("conformance/pyproject.toml").read_text())["project"]["version"]
if os.environ["RELEASE_TAG"] != "conformance-v" + version:
raise SystemExit("Conformance release tag does not match package version")
PY
testpypi:
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi' && vars.CONFORMANCE_TESTPYPI_ENABLED == 'true'
needs: build
runs-on: ubuntu-latest
environment: conformance-testpypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: conformance-dist
path: dist/
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
repository-url: https://test.pypi.org/legacy/
pypi:
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, 'conformance-v') && vars.CONFORMANCE_PYPI_ENABLED == 'true'
needs: [build, tag]
runs-on: ubuntu-latest
environment: conformance-pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: conformance-dist
path: dist/
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
104 changes: 60 additions & 44 deletions .github/workflows/require-maintainer-approval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,70 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const MAINTAINERS = ['imran-siddique', 'lywinged', 'pforest', 'Qiang-Xu', 'rajnisht7'];

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 !== "c5cfa00e1c62ca1b4da2b999fc16e943dad09d90") throw error;
file = { encoding: 'base64', content: Buffer.from(JSON.stringify({"schema":1,"repository":"trace-spec","source":"agentrust-io/.github:maintainers/roster.json","maintainers":["imran-siddique","lywinged","pforest","Qiang-Xu","rajnisht7"],"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);
}
4 changes: 2 additions & 2 deletions CHARTER.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The project includes:

- **The TRACE Specification**: normative text defining the Trust Record schema, wire format, signing and key management protocol, verification rules, hardware root profiles, and conformance requirements.
- **JSON Schema**: machine-readable schema for Trust Record validation.
- **Conformance test suite**: the canonical tests validating compliance (in [agentrust-io/trace-tests](https://github.com/agentrust-io/trace-tests)).
- **Conformance test suite**: the canonical tests validating compliance (in [trace-spec/conformance](https://github.com/agentrust-io/trace-spec/tree/main/conformance)).
- **Vendor platform annexes**: informative, vendor-co-authored claim-mapping documents for each silicon and cloud attestation surface.
- **Reference examples**: example Trust Records for each supported hardware platform.

Expand Down Expand Up @@ -55,7 +55,7 @@ Use of "TRACE-conformant" to describe an implementation is permitted only when t

## 6. Conformance

An implementation may claim TRACE conformance only by passing the conformance test suite in [agentrust-io/trace-tests](https://github.com/agentrust-io/trace-tests) at the level being claimed (Level 0, 1, or 2). Conformance claims must reference the test suite version and include a link to a passing run.
An implementation may claim TRACE conformance only by passing the conformance test suite in [trace-spec/conformance](https://github.com/agentrust-io/trace-spec/tree/main/conformance) at the level being claimed (Level 0, 1, or 2). Conformance claims must reference the test suite version and include a link to a passing run.

Test suite changes that would invalidate previously conformant implementations require a spec version increment.

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to TRACE

TRACE is an open specification. Contributions are welcome in four areas: the specification text, the JSON Schema, the examples, and the conformance test suite (in [agentrust-io/trace-tests](https://github.com/agentrust-io/trace-tests)).
TRACE is an open specification. Contributions are welcome in four areas: the specification text, the JSON Schema, the examples, and the conformance test suite (in [trace-spec/conformance](https://github.com/agentrust-io/trace-spec/tree/main/conformance)).

## Running the reference-library checks

Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Roadmap

Status as of September 2026. Spec **v0.2** is current ([`spec/trace-v0.2.md`](spec/trace-v0.2.md)); the `agentrust-trace` reference SDK is at **0.11.0** and the conformance suite (`agentrust-io/trace-tests`) at **0.5.1**.
Status as of September 2026. Spec **v0.2** is current ([`spec/trace-v0.2.md`](spec/trace-v0.2.md)); the `agentrust-trace` reference SDK is at **0.11.0** and the conformance suite (`trace-spec/conformance`) at **0.5.1**.

## Shipped: v0.2 (July to August 2026)

Expand Down
16 changes: 16 additions & 0 deletions docs/repository-consolidation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ python -m pytest -v --tb=short
3. Configure a trusted PyPI publisher for the existing package from trace-spec with a separate workflow and release policy. Root library tags must not release the conformance package accidentally. Verify a release from the new publisher before retiring the original release workflow.
4. Move the tests.agentrust-io.com deployment to a host supporting a second site from this repository, or a dedicated deployment repository. A second gh-deploy in trace-spec would overwrite the specification site, so this PR only builds the tests documentation. Keep the existing source deployment active until the replacement is verified.
5. Add a moved notice to the original README and archive trace-tests only after the consumer, release and site cutovers. Retain its Git history, releases and issues; never delete the repository.

## Prepared publisher handover

`conformance-publish.yml` reuses the installed-artifact package build. Its manual default only builds. Root library release tags are ignored; conformance releases use `conformance-v<package-version>` and must match `conformance/pyproject.toml`. Publication is disabled unless its explicit repository variable is `true`.

Before enabling either publisher:

1. Configure the existing `agentrust-trace-tests` project with repository `agentrust-io/trace-spec`, workflow `conformance-publish.yml`, and the matching environment: `conformance-testpypi` or `conformance-pypi`.
2. Configure independent environment approval and verify two available package owners/release operators. Louie and Rajnish are the proposed operators; their package access is not yet verified.
3. Set `CONFORMANCE_TESTPYPI_ENABLED=true` only after its TestPyPI binding and approvals are ready. Run the manual TestPyPI target and verify the installed artifact.
4. Enable `CONFORMANCE_PYPI_ENABLED=true` only after the production binding and approval requirements are verified. Publish an approved, previously unpublished conformance version; do not republish an existing version or bump versions solely for migration.
5. Link the successful production run and installed-package verification before retiring the old publisher.

The workflow is prepared, not evidence that a trusted publisher or environment has been configured. Keep the original release path active until verification.

For documentation, use a host supporting a separate project/site from the same repository, with `conformance/` as its project root. Existing `conformance-docs.yml` builds the site artifact. Verify the separate deployment and custom domain before changing DNS or retiring the original site. Do not deploy that artifact to the specification's GitHub Pages site.
Loading