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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ project uses [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.6.3] - 2026-10-30

The Action is listed on GitHub Marketplace as "ControlLoop Security". The
CLI is unchanged.

### Changed

- **The Action's name is `ControlLoop Security`**, which is what
Marketplace shows, instead of `ControlLoop gate`. Plain `ControlLoop`
isn't available: Marketplace refuses a name that matches another
account, and the `controlloop` organization is not this project's.
Workflows reference the Action by repository and tag, so nothing that
uses it changes.

### Added

- **`controlloop mcp`, a local MCP server.** An agent host that speaks MCP
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ In a container, with no network:

```bash
docker run --rm --network none -v "$PWD:/work:ro" \
ghcr.io/controlloop-security/controlloop:0.6.2 scan /work
ghcr.io/controlloop-security/controlloop:0.6.3 scan /work
```

Every install path, with its verification step, is in
Expand All @@ -162,7 +162,7 @@ uv run controlloop --version
```

```text
ControlLoop 0.6.2
ControlLoop 0.6.3
Supported OASF versions: none yet
Agent host key sets (documentation read on): claude-code 2026-10-17, codex 2026-10-17, cursor 2026-10-17, gemini-cli 2026-10-17, kiro 2026-10-17, roo-code 2026-10-29
Rule pack: controlloop-community 0.9.0 (24 rules)
Expand Down Expand Up @@ -523,7 +523,7 @@ controlloop rules
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0 # gate needs real history for a baseline
- uses: controlloop-security/controlloop@v0.6.2 # a release tag or commit SHA
- uses: controlloop-security/controlloop@v0.6.3 # a release tag or commit SHA
with:
path: ${{ github.workspace }}
```
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# `description` is what GitHub Marketplace lists, and Marketplace refuses
# one of 125 characters or more; tests/test_action_metadata.py holds it
# under that.
name: ControlLoop gate
name: ControlLoop Security
description: >-
Block pull requests that widen what an AI agent can do, from agent
configs, MCP servers and framework code.
Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ controlloop --version
```

```text
ControlLoop 0.6.2
ControlLoop 0.6.3
Supported OASF versions: none yet
Agent host key sets (documentation read on): claude-code 2026-10-17, codex 2026-10-17, cursor 2026-10-17, gemini-cli 2026-10-17, kiro 2026-10-17, roo-code 2026-10-29
Rule pack: controlloop-community 0.9.0 (24 rules)
Expand Down Expand Up @@ -162,7 +162,7 @@ docker run --rm --network none -v "$PWD:/work:ro" \

Verify by running it with `--version` in place of `scan /work`. The image
is published for every tagged release, tagged by exact version only
(`0.6.2`, not `latest`); the release notes record
(`0.6.3`, not `latest`); the release notes record
its digest, and `gh attestation verify
oci://ghcr.io/controlloop-security/controlloop:<version> --repo
controlloop-security/controlloop` checks its provenance. What is in the
Expand Down
12 changes: 6 additions & 6 deletions docs/reference/marketplace-listing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ updated: 2026-10-30
# Action marketplace listing

**The GitHub Action is listed on GitHub Marketplace** as
[ControlLoop gate](https://github.com/marketplace/actions/controlloop-gate),
from release `v0.6.2`. It works from any workflow
(`uses: controlloop-security/controlloop@v0.6.2`); the listing makes it
[ControlLoop Security](https://github.com/marketplace/actions/controlloop-gate),
from release `v0.6.3`. It works from any workflow
(`uses: controlloop-security/controlloop@v0.6.3`); the listing makes it
discoverable from Marketplace search. This page
records what is prepared and the steps a maintainer takes to publish it.

Expand All @@ -26,7 +26,7 @@ From GitHub's [publishing guide](https://docs.github.com/en/actions/how-tos/crea
| --- | --- |
| The repository is public | Yes |
| One action metadata file, at the root | `action.yml` |
| A unique `name` that matches no existing action, category, user, or organization | `ControlLoop gate` |
| A unique `name` that matches no existing action, category, user, or organization | `ControlLoop Security`. Plain `ControlLoop` is refused: it matches the `controlloop` organization, which is not this project's. |
| A `description` shorter than 125 characters | 107 characters, held under the limit by `tests/test_action_metadata.py` |
| The owning account accepts the GitHub Marketplace Developer Agreement | A maintainer does this once, in the publish form |
| Two-factor authentication on the publishing account | Required when the release is published |
Expand All @@ -45,7 +45,7 @@ releases for `controlloop-security/controlloop`. It is public, and the
listing stays up until a maintainer removes it.

1. Open the release to list, for example
`https://github.com/controlloop-security/controlloop/releases/tag/v0.6.2`,
`https://github.com/controlloop-security/controlloop/releases/tag/v0.6.3`,
and choose **Edit** (for a new release, start from **Draft a new
release**).
2. Under **Release action**, check **Publish this Action to the GitHub
Expand Down Expand Up @@ -82,7 +82,7 @@ own. (A `vMAJOR` tag like `v1` has no dot, so it could never match this
workflow's own `v*.*.*` trigger glob and re-trigger a release -- but the
invariant is broader than self-triggering risk, so it is kept intact.)

Release tags `v0.1.1` through `v0.6.2` exist (`v0.6.1` was tagged but
Release tags `v0.1.1` through `v0.6.3` exist (`v0.6.1` was tagged but
never published). No floating tag exists yet,
and none is needed before 1.0: during `0.x` every minor release may
change behavior, so consumers should pin an exact tag. From `v1.0.0` on,
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/pre-commit-hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ stays in verdict-parity with CI.
against [pre-commit](https://pre-commit.com)'s own official manifest
schema and was exercised end to end with `pre-commit try-repo` while this
page was written. Pin `rev:` to a release tag (`v0.1.1` through
`v0.6.2` exist) or a commit SHA.
`v0.6.3` exist) or a commit SHA.

## Minimal usage

```yaml
repos:
- repo: https://github.com/controlloop-security/controlloop
rev: v0.6.2 # a release tag or commit SHA, never an unpinned/"latest" ref
rev: v0.6.3 # a release tag or commit SHA, never an unpinned/"latest" ref
hooks:
- id: controlloop-gate
```
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "controlloop"
version = "0.6.2"
version = "0.6.3"
description = "Local-first security scanner and deterministic CI gate for AI agents"
license = "Apache-2.0"
license-files = ["LICENSE", "NOTICE"]
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/golden/agent-with-ceiling-breach/acbom.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"diagnostics":[],"digest":"sha256:b5134f82db04f012df942b2cbe8f9ef0350f2413e057db6c5ea933f9633fa51b","edges":[{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"source":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","status":"direct","target":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","type":"invokes"}],"generator":{"name":"controlloop","version":"0.6.2"},"nodes":[{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","name":"refund-agent","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"standards_identifiers":[],"subtype":"a2a-agent-card","type":"agent"},{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","name":"delete-database","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"standards_identifiers":[],"subtype":"a2a-skill","type":"tool"}],"repository":{"commit":"unknown","root_digest":"sha256:894ae1959cd35ccc1a3be5b96d4867df4db18c16e6f4b5d4b6ef495fba7d1db9"},"schema_url":"https://schemas.controlloop.ai/acbom/1.2.0/acbom.schema.json","schema_version":"1.2.0"}
{"diagnostics":[],"digest":"sha256:7062c91c59b61d8ad8030003e580cd9a58e64c2e4ae820140a31f53284e1e2b4","edges":[{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"source":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","status":"direct","target":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","type":"invokes"}],"generator":{"name":"controlloop","version":"0.6.3"},"nodes":[{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","name":"refund-agent","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"standards_identifiers":[],"subtype":"a2a-agent-card","type":"agent"},{"confidence":"high","evidence":[{"adapter":"a2a","document_digest":null,"line_end":null,"line_start":null,"parser":null,"path":"agent-card.json","schema_id":null}],"id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","name":"delete-database","security_attributes":{"approval_present":null,"code_execution":null,"data_classifications":[],"destructive":null,"external_communication":null,"financial_action":null,"permission_scopes":[],"privileged":null,"read_only":null,"requires_approval":null,"sensitivity":null,"trusted":null},"standards_identifiers":[],"subtype":"a2a-skill","type":"tool"}],"repository":{"commit":"unknown","root_digest":"sha256:894ae1959cd35ccc1a3be5b96d4867df4db18c16e6f4b5d4b6ef495fba7d1db9"},"schema_url":"https://schemas.controlloop.ai/acbom/1.2.0/acbom.schema.json","schema_version":"1.2.0"}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"schema_version":"1.2.0","verdict":"deployment_blocked","blast_radius":null,"material_changes":null,"findings":[{"schema_version":"1.1.0","id":"clp:finding:sha256:3935140e086b822efa69acf29b22d5c050493d7076aaf9c528a9e61fa24fd85b","rule_id":"policy.capability-ceiling","rule_version":"1.0.0","message":"agent 'refund-agent' reaches 'delete-database', which is a prohibited resource or external destination under its capability ceiling","severity":"critical","confidence":"high","affected_agent":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}],"capability_path":{"schema_version":"1.0.0","agent_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","target_type":"tool","hops":[{"edge_id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","edge_type":"invokes","source_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}]}],"confidence":"high"},"change_state":"not-compared","remediation":"narrow the discovered capability, or update the declared capability ceiling in controlloop.yaml if this authority is intended","documentation_url":"https://docs.controlloop.ai/reference/policy-rules#capability-ceiling"},{"schema_version":"1.1.0","id":"clp:finding:sha256:a86cb3610b02da19fc10d433fe4416d4161e0c529da47d146a8081f6f7de9e71","rule_id":"policy.undeclared-tools","rule_version":"1.0.0","message":"Tool 'delete-database' is reachable but not declared in controlloop.yaml.","severity":"medium","confidence":"high","affected_agent":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}],"capability_path":{"schema_version":"1.0.0","agent_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","target_type":"tool","hops":[{"edge_id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","edge_type":"invokes","source_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}]}],"confidence":"high"},"change_state":"not-compared","remediation":"Declare this tool in controlloop.yaml (for example, an approvals entry naming its capability), or remove the agent's access to it if it was not intentional.","documentation_url":"https://docs.controlloop.ai/reference/policy-rules#undeclared-tools"}],"diagnostics":[],"suppressions":[],"versions":{"scanner":{"name":"controlloop","version":"0.6.2"},"acbom_schema_version":"1.2.0","report_schema_version":"1.2.0","policy_version":"0.9.0"}}
{"schema_version":"1.2.0","verdict":"deployment_blocked","blast_radius":null,"material_changes":null,"findings":[{"schema_version":"1.1.0","id":"clp:finding:sha256:3935140e086b822efa69acf29b22d5c050493d7076aaf9c528a9e61fa24fd85b","rule_id":"policy.capability-ceiling","rule_version":"1.0.0","message":"agent 'refund-agent' reaches 'delete-database', which is a prohibited resource or external destination under its capability ceiling","severity":"critical","confidence":"high","affected_agent":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}],"capability_path":{"schema_version":"1.0.0","agent_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","target_type":"tool","hops":[{"edge_id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","edge_type":"invokes","source_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}]}],"confidence":"high"},"change_state":"not-compared","remediation":"narrow the discovered capability, or update the declared capability ceiling in controlloop.yaml if this authority is intended","documentation_url":"https://docs.controlloop.ai/reference/policy-rules#capability-ceiling"},{"schema_version":"1.1.0","id":"clp:finding:sha256:a86cb3610b02da19fc10d433fe4416d4161e0c529da47d146a8081f6f7de9e71","rule_id":"policy.undeclared-tools","rule_version":"1.0.0","message":"Tool 'delete-database' is reachable but not declared in controlloop.yaml.","severity":"medium","confidence":"high","affected_agent":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}],"capability_path":{"schema_version":"1.0.0","agent_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","target_type":"tool","hops":[{"edge_id":"clp:edge:sha256:d6141860d347281ceeb951eef4be8481c1c50ce2e4c9345bdb0858a4c40b938b","edge_type":"invokes","source_id":"clp:agent:sha256:2321fe51daefbeccc66dac2ae3e63aa0237216db27510216a9f61c3faf760cf9","target_id":"clp:tool:sha256:f7824d54df66d9cf3b619974e61d0c003c85cafe2e1e019b2f960ab4f6844771","evidence":[{"adapter":"a2a","path":"agent-card.json","line_start":null,"line_end":null,"parser":null,"schema_id":null,"document_digest":null}]}],"confidence":"high"},"change_state":"not-compared","remediation":"Declare this tool in controlloop.yaml (for example, an approvals entry naming its capability), or remove the agent's access to it if it was not intentional.","documentation_url":"https://docs.controlloop.ai/reference/policy-rules#undeclared-tools"}],"diagnostics":[],"suppressions":[],"versions":{"scanner":{"name":"controlloop","version":"0.6.3"},"acbom_schema_version":"1.2.0","report_schema_version":"1.2.0","policy_version":"0.9.0"}}
2 changes: 1 addition & 1 deletion tests/fixtures/golden/empty/acbom.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"diagnostics":[],"digest":"sha256:bec64aca873343c93a3eb62772629b3e9fd2e5deba575c6a99a52e740da25465","edges":[],"generator":{"name":"controlloop","version":"0.6.2"},"nodes":[],"repository":{"commit":"unknown","root_digest":"sha256:b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5"},"schema_url":"https://schemas.controlloop.ai/acbom/1.2.0/acbom.schema.json","schema_version":"1.2.0"}
{"diagnostics":[],"digest":"sha256:67edd7e34fcfe9f0354561ede6247fe8126492237e83ea60e43f9d58b23e657a","edges":[],"generator":{"name":"controlloop","version":"0.6.3"},"nodes":[],"repository":{"commit":"unknown","root_digest":"sha256:b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5"},"schema_url":"https://schemas.controlloop.ai/acbom/1.2.0/acbom.schema.json","schema_version":"1.2.0"}
2 changes: 1 addition & 1 deletion tests/fixtures/golden/empty/report.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"schema_version":"1.2.0","verdict":"passed","blast_radius":null,"material_changes":null,"findings":[],"diagnostics":[],"suppressions":[],"versions":{"scanner":{"name":"controlloop","version":"0.6.2"},"acbom_schema_version":"1.2.0","report_schema_version":"1.2.0","policy_version":"0.9.0"}}
{"schema_version":"1.2.0","verdict":"passed","blast_radius":null,"material_changes":null,"findings":[],"diagnostics":[],"suppressions":[],"versions":{"scanner":{"name":"controlloop","version":"0.6.3"},"acbom_schema_version":"1.2.0","report_schema_version":"1.2.0","policy_version":"0.9.0"}}
Loading
Loading