Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9867c77
Add design for GitHub Pages landing page and schema hosting
rocklambros Sep 5, 2026
c4e86ee
Add implementation plan for the GitHub Pages site
rocklambros Sep 5, 2026
611b820
Rewrite the Pages plan after a six-perspective premortem
rocklambros Sep 5, 2026
d2ecf3e
Correct per-task test counts and ignore the execution workspace
rocklambros Sep 5, 2026
74c4760
Publish schemas to validated paths derived from their $id
rocklambros Sep 5, 2026
8d47086
Add the landing page, its design tokens, and the starburst diagram
rocklambros Sep 5, 2026
2c77e19
Assign the landing page guards to the task that creates them
rocklambros Sep 5, 2026
4dfc618
Correct American English and prose semicolons in the landing page
rocklambros Sep 5, 2026
65c6045
Correct American English and prose semicolons in the plan
rocklambros Sep 5, 2026
3448bce
Inject page content at build time and guard the rendered output
rocklambros Sep 5, 2026
443d956
Align the plan's test code with the corrected wording
rocklambros Sep 5, 2026
af388ce
Stop the documentation site contacting Google
rocklambros Sep 5, 2026
77b5551
Scope the origin guard to resource loads
rocklambros Sep 5, 2026
894f71c
Scope the plan's origin guard to resource loads
rocklambros Sep 5, 2026
8efd83e
Move the merge-gate claim to the task that implements it
rocklambros Sep 5, 2026
30e234a
Test, build, deploy, then verify the published bytes
rocklambros Sep 5, 2026
ff43369
Grant the plan's deploy job read access for its own checkout
rocklambros Sep 5, 2026
5864d90
Grant the deploy job read access for its own checkout
rocklambros Sep 5, 2026
30a512e
Bring policy and ownership in line with operating a site
rocklambros Sep 5, 2026
a53dded
Retire the not-yet-served note when the namespace starts resolving
rocklambros Sep 5, 2026
77f5a78
Give the plan's license rows an SPDX column and defer the hosting claim
rocklambros Sep 5, 2026
74b0d80
Give the new license rows their SPDX column and fix a hosting claim
rocklambros Sep 5, 2026
4f29dba
Name the standards ACS builds on and style the theme toggle
rocklambros Sep 5, 2026
4d1caeb
Give the documentation site the landing page's theme
rocklambros Sep 5, 2026
6e45809
Close the whole-branch review findings
rocklambros Sep 5, 2026
2a161e9
Stop the documentation site from calling the GitHub API on every page…
rocklambros Sep 5, 2026
e781703
Gate the theme overrides the way the other build inputs are gated
rocklambros Sep 5, 2026
03f9f84
Close the re-review findings
rocklambros Sep 5, 2026
9c43a63
License the overrides tree as documentation and write its partial
rocklambros Sep 5, 2026
29aac8a
Restore the repository icon in the documentation header
rocklambros Sep 5, 2026
2389bd5
Assert the header keeps its repository icon
rocklambros Sep 5, 2026
f1cae6c
Use the sun and moon for the theme control on both surfaces
rocklambros Sep 5, 2026
b67b6ba
Keep the ACS link colour against the theme's default palette
rocklambros Sep 5, 2026
b50082c
Show one mark, and stop calling the specification external
rocklambros Sep 5, 2026
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
18 changes: 18 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@
/specification/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp @afogel @stefanoamorelli @almogbhl @bar-capsule @evabenn @RbBuiltWrong @aruneeshsalhotra
/docs/spec/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp @afogel @stefanoamorelli @almogbhl @bar-capsule @evabenn @RbBuiltWrong @aruneeshsalhotra

# These generate and publish the public site, or feed the build that does. A change
# here alters what the front door says, which is the same class of privilege the
# /.github/ rule below protects. mkdocs.yml in particular accepts a hooks: key that
# executes Python inside the build job. The overrides directory holds theme templates
# the build renders into every page, which carries the same reach.
# The docs stylesheet and asset directories render into every documentation page and
# can reach a third party through url(), @font-face, or @import with no script at all.
/tools/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/landing/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/GOVERNANCE.md @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/mkdocs.yml @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/pyproject.toml @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/uv.lock @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/tests/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/overrides/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/docs/stylesheets/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
/docs/assets/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp

# CI runs with write access to the repository. Changes here are a
# privilege-escalation surface and warrant admin review.
/.github/ @rocklambros @fewdisc @GangGreenTemperTatum @mamicidal @sclintonowasp
Expand Down
121 changes: 121 additions & 0 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Builds and publishes the landing page, the documentation site, and the JSON schemas.
# Pull requests test and build without deploying. Merge to main publishes with no human
# in the loop, so every guard runs here rather than on a contributor's laptop.
name: Deploy Pages

on:
push:
branches: ["main"]
pull_request:
workflow_dispatch:

# Deny by default. Each job grants itself only what it needs.
permissions: {}

# One group for every deploy so they serialize on the single Pages site they share.
# Pull request builds group per ref and cancel stale runs. Keying everything on ref
# would let a dispatch on a branch deploy alongside a push to main.
concurrency:
group: pages-${{ github.event_name == 'pull_request' && github.ref || 'deploy' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.9.9"

- name: Install dependencies from the lockfile
run: uv sync --locked

- name: Run the guards
run: uv run pytest -v

build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
# configure-pages calls GET /repos/{owner}/{repo}/pages, which needs this.
pages: read
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.9.9"

- name: Install dependencies from the lockfile
run: uv sync --locked --no-dev

- name: Configure Pages
id: pages
# Skipped on pull requests. The action fails when Pages is not yet enabled, and
# a fork's token cannot read the Pages API at all. Pull requests only need a
# site_url, and the constant below is correct for them.
if: github.event_name != 'pull_request'
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- name: Build the documentation site
env:
# mkdocs.yml reads site_url from this, and MkDocs builds into _site/docs/, so
# the value must name the docs subpath. Passing the site root makes every
# canonical URL and every sitemap entry omit /docs/ and resolve to a 404.
GITHUB_PAGES_URL: ${{ steps.pages.outputs.base_url && format('{0}/docs/', steps.pages.outputs.base_url) || 'https://genai-security-project.github.io/agent-control-standard/docs/' }}
run: uv run --no-dev mkdocs build --strict -d _site/docs

- name: Render the landing page
run: uv run --no-dev python tools/render_landing.py landing _site

- name: Publish the schemas
# Fails when any $id is unsafe or duplicated, or any $ref does not resolve.
run: uv run --no-dev python tools/publish_schemas.py specification _site/schema

- name: Upload the artifact
if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: _site
# The default is one day, which would expire the fastest rollback path:
# re-running the deploy job of the last good run.
retention-days: 30

deploy:
# event_name alone is not enough. workflow_dispatch can target any ref, so without
# the branch check a feature branch could publish to the production site.
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Deploy to Pages
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1

- name: Verify the published schemas
# Through env, never interpolated into the shell. sync_version.yml documents why.
env:
PAGE_URL: ${{ steps.deployment.outputs.page_url }}
run: |
python3 tools/verify_published.py "$PAGE_URL" \
schema/v0.1.0/acs_schema.json \
schema/v0.1.0/hooks/session-start.json
27 changes: 27 additions & 0 deletions .github/workflows/monitor-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# The published $id URIs are a machine-consumed contract. Between merges nothing else
# checks that they still resolve, so this does.
name: Monitor Pages

on:
schedule:
- cron: "17 */6 * * *"
workflow_dispatch:

permissions: {}

jobs:
check:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Verify the published schemas still resolve
env:
PAGE_URL: https://genai-security-project.github.io/agent-control-standard/
run: |
python3 tools/verify_published.py "$PAGE_URL" \
schema/v0.1.0/acs_schema.json \
schema/v0.1.0/hooks/session-start.json
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ references/
# Python build artifacts from `uv pip install -e .`
*.egg-info/
__pycache__/

# Subagent-driven development scratch. Never committed.
.superpowers/
_site/
40 changes: 37 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,51 @@ This is a documentation-focused project built with:
- **MkDocs Material** for local documentation preview

### Hosting (decoupled from this repo)
This repository is the **source of truth for the ACS spec** (schema, hooks, events, AgBOM definitions, written specification). The marketing and docs site at **agentcontrolstandard.org** is built and deployed independently from a separate repository — changes here do not propagate automatically. The `.ai` and `.com` domains redirect to `.org`.
This repository is the source of truth for the ACS spec, and it now carries the workflow
that publishes the site. Once Pages is enabled, `.github/workflows/deploy-pages.yml`
builds three things on every merge to `main`: the landing page from `landing/`, the
MkDocs documentation under `/docs/`, and the JSON schemas under `/schema/<spec-version>/`.

Schema publish paths derive from each schema's own `$id`, which is validated and
contained because `$id` is a pull-request-writable string used to build a filesystem
path. The build fails on an unsafe or duplicated `$id` and on any `$ref` that does not
resolve, fragment included.

`GOVERNANCE.md` is a build input. Its workstream table renders into the published page,
so a change to its shape can fail the deploy, and its contents are escaped as untrusted
text.

The marketing site at **agentcontrolstandard.org** is still built and deployed from a
separate repository. It will redirect here later. Adding the custom domain makes GitHub
301 the `github.io` URIs to it, which schema tooling follows. Do not rebase `$id` onto
the marketing domain during that cutover. A `CNAME` must be written into `_site` by the
build. Placing one in `landing/` does not reach the artifact.

### Contact channels
The repository carries no email addresses, by policy. Community contact is GitHub Discussions, security reporting is GitHub private vulnerability reporting, and Code of Conduct enforcement routes to the OWASP CoC process so that a report about a maintainer does not land with the maintainers. Do not add a contact address to documentation, `project.owasp.yaml`, or the site config. Example addresses in specification documents must use the RFC 2606 reserved domains (`example.com`, `example.net`, `example.org`).
The repository carries one contact address and no others. `rock.lambros@owasp.org`
appears on the landing page for general questions about the project. Do not add any
other contact address to documentation, `project.owasp.yaml`, or the site config.

Routing is unchanged. Community contact is GitHub Discussions and the
`#team-genai-asi-acs-general` channel on `owasp.slack.com`. Security reporting is GitHub
private vulnerability reporting, which is the channel `SECURITY.md` covers. Code of
Conduct enforcement routes to the OWASP CoC process so that a report about a maintainer
does not land with the maintainers. The landing page links both, so publishing an
address does not pull reports out of the processes that handle them independently.

Example addresses in specification documents must use the RFC 2606 reserved domains
(`example.com`, `example.net`, `example.org`). Eleven of these exist in `docs/` today
and are correct.

### Schema namespace
Schema `$id` values are based at `https://genai-security-project.github.io/agent-control-standard/schema/<spec-version>/`, not at any of the project domains. The namespace follows the org and repo so that schema identity survives a domain or hosting change. Do not rebase `$id` onto a marketing domain.

`$id` is identity, not a fetch target. Every `$ref` in the package is relative and resolves against the enclosing `$id` base, so the whole set must share one base. Two bases means the relative refs resolve to URIs no `$id` declares, which is the defect fixed in `4fb84c1`. If you add a subschema, give it an `$id` under the same base and keep its refs relative.

The base is not yet served: GitHub Pages is not enabled on this repo, so remote retrieval 404s. Local and file-path validation is unaffected.
The base is served once GitHub Pages is enabled on this repository, which
`.github/workflows/deploy-pages.yml` then publishes to on every merge to `main` and
`.github/workflows/monitor-pages.yml` rechecks every six hours. Until that setting is
turned on, remote retrieval 404s and only local and file-path validation works.

`$id` is versioned by **spec** version, not release version. `.github/workflows/sync_version.py` deliberately leaves `$id` alone. See `1af1f92`.

Expand Down
14 changes: 12 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ All submissions go through GitHub pull request review. See [GitHub's PR guide](h
## Development Process

1. **Fork the repository** and clone your fork
2. **Create a feature branch** — use `feature/<short-description>` or `fix/<short-description>`
2. **Create a feature branch.** Use `feature/<short-description>` or `fix/<short-description>`
3. **Make your changes** following the style guide
4. **Sign your commits** with `git commit -s` (required by the DCO below)
5. **Open a pull request** against `main`
6. **Address review feedback** to land your change

For changes to the spec itself (`acs_schema.json`, hooks, events), open a [Discussion](https://github.com/GenAI-Security-Project/agent-control-standard/discussions) before submitting a PR — these affect downstream implementers and warrant a longer conversation.
For changes to the spec itself (`acs_schema.json`, hooks, events), open a [Discussion](https://github.com/GenAI-Security-Project/agent-control-standard/discussions) before submitting a PR. These affect downstream implementers and warrant a longer conversation.

## What We Need

Expand Down Expand Up @@ -89,6 +89,16 @@ By contributing, you agree that your contributions will be licensed under the li

This guide is based on [github-contributing](https://raw.githubusercontent.com/standard/.github/refs/heads/master/CONTRIBUTING.md).

## Before the first Pages deploy

`.github/workflows/deploy-pages.yml` and `.github/workflows/monitor-pages.yml` both
assume GitHub Pages is already enabled for this repository. Until it is, the deploy fails
at the Configure Pages step and the monitor fails on its schedule.

Enabling it is a one-time repository setting, done by an administrator: Settings, then
Pages, then set Build and deployment Source to GitHub Actions. Do this before merging any
change that turns those workflows on, not after.

## Community

- **[GitHub Discussions](https://github.com/GenAI-Security-Project/agent-control-standard/discussions)**: Ask questions, share ideas
Expand Down
27 changes: 26 additions & 1 deletion LICENSING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ Copyright 2025-2026 The OWASP GenAI Security Project and the ACS contributors.
| Code samples embedded in any Markdown file | Apache License 2.0 | `Apache-2.0` |
| `docs/**` | CC BY-SA 4.0 | `CC-BY-SA-4.0` |
| `README.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `CONTRIBUTORS.md`, `STYLE.md`, `SPEC_REVIEW_PRINCIPLES.md`, `LICENSING.md` | CC BY-SA 4.0 | `CC-BY-SA-4.0` |
| `landing/**`, `tools/**`, `tests/**` | Apache License 2.0 | `Apache-2.0` |
| `overrides/**` | CC BY-SA 4.0 | `CC-BY-SA-4.0` |
| `design/**` | CC BY-SA 4.0 | `CC-BY-SA-4.0` |
| `landing/assets/fonts/**` | SIL Open Font License 1.1 | `OFL-1.1` |

Full texts live in [`LICENSE`](./LICENSE) for Apache 2.0 and [`LICENSE-DOCS`](./LICENSE-DOCS) for CC BY-SA 4.0. Attribution details live in [`NOTICE`](./NOTICE).
Full texts live in [`LICENSE`](./LICENSE) for Apache 2.0, [`LICENSE-DOCS`](./LICENSE-DOCS) for CC BY-SA 4.0, and [`landing/assets/fonts/OFL.txt`](./landing/assets/fonts/OFL.txt) for the SIL Open Font License 1.1. Attribution details live in [`NOTICE`](./NOTICE).

Code samples inside the documentation carry the Apache 2.0 grant, not the ShareAlike obligation. Copy a JSON payload or a hook definition out of `docs/` into a proprietary agent and nothing forces you to open-source the result.

Expand Down Expand Up @@ -52,3 +56,24 @@ These licenses cover copyright. They grant no rights to the OWASP name, the OWAS
## License history

Releases up to and including v0.1.0 were published under the MIT License. That grant stands. Anyone who obtained ACS under the MIT License keeps their rights under it. Contributions merged after the relicense are governed by the terms on this page.

## Provenance of the landing page design

The design tokens in `landing/assets/acs.css`, the diagram geometry in
`landing/assets/starburst.svg`, and the mark in `landing/assets/icon.svg`, which is
duplicated at `docs/assets/icon.svg` because MkDocs requires a theme logo inside its own
documentation directory, derive from agentcontrolstandard.org, which the OWASP GenAI
Security Project operates and which is built from a separate repository. They are used
here as the project's own work. Both copies of the mark are covered by the
`landing/**` row above.

The OWASP GenAI Security Project holds the rights to this design, confirmed by the
project lead. No outside party has a claim on the tokens, the diagram geometry, or the
mark, so they are covered by the rows above with no further condition.

The vendored font is Inter, redistributed under the SIL Open Font License 1.1. Its
recorded checksum is in `landing/assets/fonts/CHECKSUMS.txt`.

The documentation header inlines the GitHub mark from the Simple Icons set bundled with
Material for MkDocs, dedicated to the public domain under CC0 1.0 Universal. It is
included at build time rather than vendored, so no copy lives in this repository.
4 changes: 4 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Apache License, Version 2.0. See LICENSE.
Prose documentation in this repository is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License. See LICENSE-DOCS.

The landing page bundles the Inter typeface, Copyright (c) 2016 The Inter Project
Authors (https://github.com/rsms/inter), licensed under the SIL Open Font License,
Version 1.1. See landing/assets/fonts/OFL.txt.

See LICENSING.md for the full scope map.

Prior history: releases up to and including v0.1.0 were published under the MIT
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The standard covers the following aspects

## Getting Started

- 📚 **Explore the Documentation:** Visit the [Documentation Site](https://agentcontrolstandard.ai) for a complete overview, the full specification, tutorials, and guides.
- 📚 **Explore the Documentation:** Once GitHub Pages is enabled, visit the [documentation site](https://genai-security-project.github.io/agent-control-standard/docs/) for a complete overview, the full specification, tutorials, and guides. The [project landing page](https://genai-security-project.github.io/agent-control-standard/) covers what ACS is and why it exists.
- 📝 **View the Specification:** [Specification](https://github.com/GenAI-Security-Project/agent-control-standard/tree/main/specification)

## Contributing
Expand Down
5 changes: 4 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ Partial reports are welcome. We would rather triage something incomplete than ne

| In scope | Out of scope |
| --- | --- |
| Flaws in the ACS specification that lead implementers into insecure designs | The documentation site at agentcontrolstandard.ai, which is built from a separate repository |
| Flaws in the ACS specification that lead implementers into insecure designs | The marketing site at agentcontrolstandard.org, which is built and deployed from a separate repository |
| Errors in the JSON Schemas under `specification/` | Findings against third-party agent frameworks that happen to implement ACS |
| The GitHub Actions workflows in `.github/workflows/` | Automated scanner output with no demonstrated impact |
| Hook or event definitions that leak sensitive data by design | Missing security headers on sites we do not operate |
| Supply-chain issues in this repository's dependencies | Social engineering of maintainers or contributors |
| The published site at genai-security-project.github.io/agent-control-standard once Pages is enabled, including the landing page, the documentation, and the schema endpoints | |
| The build and publish tooling in `tools/` and `.github/workflows/` | |
| | Missing security response headers on the Pages site, which GitHub Pages does not allow us to set |

A specification flaw counts. If a hook definition forces implementers to log secrets, or an event schema makes an authorization bypass easy to write, that is a finding even though no code here executes.

Expand Down
Loading