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
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

Tools to let coding agents access the shell with opinionated defaults.

## Security model

Most agent actions should run under [`//sandbox`](sandbox/BUILD.bazel).
Command filtering complements sandboxing by narrowly delegating selected CLI
capabilities, including commands that intentionally use the user's ambient
credentials. It is not a substitute for sandboxing.

Command filtering is useful for narrowing which command lines an agent may run:
which binaries are allowed, which subcommands and flags are allowed, and which
logical paths may be passed as arguments. That is a least-authority delegation
mechanism, not a full security boundary.

If an allowed command can use the user's ambient credentials, network access,
or other external authority, then allowing that command is effectively
granting that capability to the agent. Path restrictions such as `<path:r>`
and `<path:w>` only constrain named file arguments; they do not constrain
unrelated side effects a command may have.

For example, a user might grant an agent permission to fetch GitHub Actions
logs via a narrow `gh` rule. That is different from allowing arbitrary `gh`
usage: the rule is a deliberate delegation of one credential-backed
capability, not blanket authority over the GitHub CLI.

Some allowed tools may execute hooks, helpers, pagers, editors, or other
user-controlled programs as part of their normal behavior.
Rules should be written with those secondary execution paths in mind.

Practical guidance:

- Prefer running agent actions in `//sandbox`.
- Use command filters to grant narrow, reviewable capabilities, especially for
tools that intentionally act with the user's ambient credentials.
- Write rules per operation, not per binary.
- Treat each allow-rule as a permission grant that should be reviewed.

## License

Apache-2.0
Expand Down
63 changes: 51 additions & 12 deletions command_filter/LANGUAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ A small language for defining allowed command invocations. Each rule file
describes the permitted argument shapes for a command, with path arguments
carrying read/write permission annotations.

This language describes which command lines are permitted. It does not by
itself provide process isolation. In this repository, most agent actions
should run under `//sandbox`; command filtering is used to narrowly delegate
specific CLI capabilities, including commands that intentionally use ambient
user credentials.

## Statements

Every line is one of two statement types, identified by a keyword prefix:
Expand Down Expand Up @@ -33,8 +39,8 @@ act as alternatives — a command is permitted if it matches any one of them.
### `define`

Binds a name to a sub-pattern that can be referenced elsewhere. The name must
be wrapped in angle brackets and must not collide with built-in types
(`string`, `path`).
be wrapped in angle brackets and must not collide with the built-in type names
`string` or `path`.

Definitions may reference other definitions. The reference graph must be
acyclic (no recursion).
Expand All @@ -55,31 +61,41 @@ allow rg --help

Angle-bracketed names that match a single argument:

| Placeholder | Matches |
|----------------|--------------------------------------|
| `<string>` | Any argument |
| `<string:->` | Any argument (dash-allowed modifier) |
| `<path:r>` | A path the user can read |
| `<path:w>` | A path the user can write |
| `<name>` | Expands a `define`d sub-pattern |
| Placeholder | Matches |
|----------------|--------------------------------------------------|
| `<string>` | Any argument that does not start with `-` |
| `<string:->` | Any argument, including those starting with `-` |
| `<path:r>` | A path the user can read |
| `<path:w>` | A path the user can write |
| `<name>` | Expands a `define`d sub-pattern |

Modifiers (the `:` suffix, e.g. `:-`, `:r`, `:w`) are only valid on built-in
types. User-defined names must be plain `<name>` with no modifier.

User-defined names are distinguished from built-in types by their presence in
a `define` statement.

### Groups and alternatives

Parentheses group elements. Pipe separates alternatives within a group:
Parentheses `()` and square brackets `[]` both group elements. Pipe `|`
separates alternatives within the closest enclosing group:

```
(-g | -F)
(-name <string:-> | -type <string:->)
[-l | -t | -h]
```

A group matches exactly one of its alternatives.
A group matches exactly one of its alternatives. Each alternative may be a
sequence of multiple elements, where each element consumes one argument:

```
(-name <string:-> | -type <string:->) # each branch is two arguments
```

### Optional

Square brackets mark an element or group as optional (zero or one):
Square brackets mark a group as optional (zero or one):

```
[<string>]
Expand All @@ -105,6 +121,29 @@ repetition of `...`:
[-r | -f]... # zero or more of these flags
```

## Ambiguity

Patterns must be **1-unambiguous**: at every point where matching could follow
two paths (continue a repetition vs. advance to the next element, or choose
between alternatives), the sets of arguments each path accepts must be
disjoint. The matcher decides where each argument belongs by inspecting that
argument alone, with no lookahead or backtracking.

A pattern that violates this property is rejected at parse time:

```
<path:r>... <path:w> # error: both sides accept paths
[<string>]... <string> # error: same type on both sides
[<string:->]... <string> # error: <string:-> is a superset of <string>
```

Valid patterns keep choice points disjoint:

```
[-v | -r]... <string> # ok: literals are disjoint from <string>
[<options>]... <string> # ok: options expand to dash-prefixed flags
```

## Future extensions

The keyword-prefixed design reserves space for future statement types (e.g.
Expand Down
Loading