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
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,25 @@ Three languages, one repo:

See [Architecture overview](https://openagentlock.github.io/OpenAgentLock/architecture/overview/) for the why behind the split.

## The five gates
## Policy — registry-first

Every install ships [`policies/default.yaml`](policies/default.yaml) with five gates in monitor mode:
OpenAgentLock ships with a minimal first-boot policy (a single `rogue.destructive-bash` gate in monitor mode) so every session has *some* policy hash to attest against. Real coverage comes from the [openagentlock/rules](https://github.com/openagentlock/rules) registry — install whichever rules match your threat model:

| Gate | What it catches |
|---|---|
| `supply-chain.pkg-install` | `pip install`, `npm install`, `brew install`, `cargo install` |
| `supply-chain.untrusted-mcp` | MCP server with an unpinned public key |
| `rogue.secret-read` | reads of `.env`, `~/.ssh`, `~/.aws/credentials`, anywhere a secret-shaped path appears |
| `rogue.net-egress` | `curl`, `wget`, MCP HTTP tools |
| `rogue.destructive-bash` | `rm -rf`, `git push --force`, `DROP TABLE`, `kubectl delete` |
```bash
agentlock rules sync # tap the upstream registry
agentlock rules search exfil # browse by keyword
agentlock rules install rogue.destructive-bash # land a gate in the live policy
agentlock rules install exfil.curl-with-env
agentlock rules install rogue.secret-read
```

You can also tap a private registry (any Git repo with the same layout) for org-internal rules:

```bash
agentlock rules add https://github.com/your-org/your-rules.git
```

See [Policies and the five gates](https://openagentlock.github.io/OpenAgentLock/guide/policies/) for the rule schema and authoring rules.
See [Policies and rules](https://openagentlock.github.io/OpenAgentLock/guide/policies/) for the schema and authoring guide.

## Repository layout

Expand All @@ -133,7 +139,6 @@ control-plane/ Go HTTP service in Docker — ghcr.i
Dockerfile, docker-compose.yml
dashboard-ui/ Vite SPA embedded into the Go binary
ledger/ Rust crate (lib + cdylib + staticlib) — openagentlock-ledger
policies/default.yaml baseline policy shipped with every install
docs/ MkDocs Material site (deployed to openagentlock.github.io/OpenAgentLock)
assets/ logo, favicon, social card
docker-compose.yml one-command control-plane bring-up
Expand Down
7 changes: 5 additions & 2 deletions control-plane/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,14 @@ RUN install -d -m 0700 -o 65532 -g 65532 /out/agentlock-home
FROM gcr.io/distroless/cc-debian12 AS runtime
COPY --from=go-builder /out/control-plane /usr/local/bin/agentlockd
COPY --from=go-builder --chown=65532:65532 /out/agentlock-home /var/lib/agentlock
COPY policies/default.yaml /etc/agentlock/policies/default.yaml
# No bundled policy file — daemon falls back to the built-in
# minimal monitor-mode policy in main.go (single rogue.destructive-bash
# gate). Operators install community rules via `agentlock rules sync`
# + `agentlock rules install <id>`. To pin a custom file, mount it
# and set AGENTLOCK_POLICY=/path/to/policy.yaml.
ENV AGENTLOCK_LISTEN=0.0.0.0:7878
ENV AGENTLOCK_DASHBOARD_LISTEN=0.0.0.0:7879
ENV AGENTLOCK_HOME=/var/lib/agentlock
ENV AGENTLOCK_POLICY=/etc/agentlock/policies/default.yaml
ENV AGENTLOCK_IN_CONTAINER=1
# Default to unattested so `docker run` works zero-conf. TUI + dashboard
# show the red "UNATTESTED — LEDGER NOT SIGNED" banner. Override with
Expand Down
12 changes: 10 additions & 2 deletions control-plane/cmd/control-plane/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,13 @@ func splitHostPort(addr string) (host, port string, ok bool) {
}

// loadPolicy reads $AGENTLOCK_POLICY if set; otherwise returns a built-in
// safe default (monitor mode, destructive-bash only) so the daemon always
// starts with *some* policy bound to session attestations.
// minimal default (monitor mode, single destructive-bash gate) so the
// daemon always starts with *some* policy bound to session attestations.
// The first-boot expectation is that operators run
// `agentlock rules sync && agentlock rules install <id>` against the
// openagentlock/rules registry to populate real coverage. The bundled
// `policies/default.yaml` was deprecated and removed — registry-first
// is the new shape (see docs/guide/policies.md).
func loadPolicy(path string) (*policy.Policy, error) {
if path == "" {
return policy.LoadBytes([]byte(defaultPolicyYAML))
Expand All @@ -171,6 +176,9 @@ func loadPolicy(path string) (*policy.Policy, error) {
return policy.Load(f)
}

// defaultPolicyYAML is the minimal first-boot policy. It exists only so
// every session has a non-empty policy hash to attest against. Operators
// are expected to layer real coverage from openagentlock/rules on top.
const defaultPolicyYAML = `
version: 1
mode: monitor
Expand Down
53 changes: 13 additions & 40 deletions docs/guide/policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,50 +66,23 @@ If a rule id collides between two registries the CLI errors out and asks you to

When the catalog doesn't have what you need, the [openagentlock/skills](https://github.com/openagentlock/skills) toolkit ships agent skills (Claude Code, Cursor, Codex) that turn natural-language intent into a `rule.yaml` and run `agentlock rules install` to land it. See the `block-pattern` skill for the canonical "block this command shape" flow.

## The five built-in defaults
## First-boot policy

When the daemon boots, it loads `policies/default.yaml`, which ships these five gates in monitor mode. They are intentionally narrow — most operators leave them on and add registry rules on top.
When the daemon boots without `AGENTLOCK_POLICY` pointing at a custom file, it loads a built-in minimal policy: a single `rogue.destructive-bash` gate in monitor mode. This exists only so every session has a non-empty policy hash to attest against — it is **not** meant as production coverage. The previously-bundled `policies/default.yaml` (with five hardcoded gates) was deprecated and removed.

<div class="gate-grid" markdown>
Real coverage comes from the registry. Recommended starting set:

<div class="gate-card" markdown>
#### Package install
<span class="gate-id">`supply-chain.pkg-install`</span>

`pip install`, `npm install`, `brew install`, `cargo install`. Catches typosquats and build-time exfiltration.
</div>

<div class="gate-card" markdown>
#### Untrusted MCP
<span class="gate-id">`supply-chain.untrusted-mcp`</span>

MCP server with an unpinned public key. Fingerprints land in `/v1/mcp/pin`.
</div>

<div class="gate-card" markdown>
#### Secret reads
<span class="gate-id">`rogue.secret-read`</span>

Reads of `.env`, `~/.ssh`, `~/.aws/credentials`, anywhere a secret-shaped path appears in the command.
</div>

<div class="gate-card" markdown>
#### Network egress
<span class="gate-id">`rogue.net-egress`</span>

`curl`, `wget`, MCP HTTP tools. Pre-execution.
</div>

<div class="gate-card" markdown>
#### Destructive bash
<span class="gate-id">`rogue.destructive-bash`</span>

`rm -rf`, `git push --force`, `DROP TABLE`, `kubectl delete`.
</div>

</div>
```bash
agentlock rules install rogue.destructive-bash # tighter regex than the bootstrap gate
agentlock rules install rogue.secret-read # deny reads of .env / .ssh / .aws / credentials
agentlock rules install rogue.net-egress # block curl/wget/POST shapes
agentlock rules install supply-chain.npm-untrusted # block installs from URL/git/tarball
agentlock rules install supply-chain.pip-untrusted # same for pip / poetry / uv
agentlock rules install exfil.curl-with-env # catch $ENV_VAR exfil shapes
agentlock rules install rogue.git-force-push # deny force-push to main/develop/release
```

The community registry has tighter / opinionated variants of several of these — e.g. `rogue.git-force-push` (only deny force-push to main / develop / release), `exfil.curl-with-env` (catch the `$ENV_VAR` exfil shape specifically), `rogue.eval-untrusted` (deny dynamic-eval shells). Install whichever match your threat model.
Browse the full catalog at <https://openagentlock.github.io/rules/>. Pin a private registry alongside the upstream for org-internal rules — see the section above.

## Authoring rules from scratch

Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ Interactive multi-select. Posts to `/v1/install/plan`, renders the diff, applies
</div>

<div class="gate-card" markdown>
#### Five baseline gates
<span class="gate-id">`policies/default.yaml`</span>
#### Registry-first policy
<span class="gate-id">`agentlock rules install`</span>

Package install, untrusted MCP, secret reads, network egress, destructive bash. Ship in monitor mode by default.
First-boot policy is intentionally minimal (one `rogue.destructive-bash` gate in monitor mode). Real coverage comes from the [openagentlock/rules](https://openagentlock.github.io/rules/) registry — `agentlock rules sync && agentlock rules install <id>` lands gates in the live policy with a fresh hash.
</div>

<div class="gate-card" markdown>
Expand Down
81 changes: 0 additions & 81 deletions policies/default.yaml

This file was deleted.

Loading