feat(mediation): DSL redesign — explicit defaults, grants, three-action set#38
Open
kipz wants to merge 1 commit into
Open
feat(mediation): DSL redesign — explicit defaults, grants, three-action set#38kipz wants to merge 1 commit into
kipz wants to merge 1 commit into
Conversation
9f7a17b to
b89b03d
Compare
christine-at-datadog
approved these changes
May 14, 2026
bffb937 to
ec9f806
Compare
b03321f to
5acc580
Compare
86b464a to
4f89e43
Compare
e1072fd to
46b6f4d
Compare
christine-at-datadog
approved these changes
Jun 5, 2026
20f53ac to
9f75de5
Compare
… pinning
Full redesign of nono's command mediation DSL and security model.
## DSL changes
**Explicit default block.** Every `mediation.commands` entry now has a
`default` with an `action` (allow/deny) and optional `sandbox`. There is
no implicit passthrough — unmatched invocations are governed by the
default, which must be declared.
**Three action types** (renamed for clarity):
- `allow` — execute the binary (was `run`). Carries optional `script`.
- `deny` — return canned stdout/stderr/exit_code without running anything
(was `respond`).
- `capture` — intercept credential-fetching commands, return a nonce,
promote to a real token only when an authorised command requests it.
**deny_unknown_fields** on all eight mediation structs (CommandSandbox,
NetworkConfig, EnvPolicy, CallerPolicy, CommandEntry, InterceptRule,
DefaultEntry, MediationConfig). Invalid profile fields are rejected at
load time rather than silently ignored.
## Authorization graph (replaces caller_policy)
- `can_use` on each `CommandEntry` — lists commands this command may
invoke as mediated children.
- `session_can_use` on `MediationConfig` — lists commands the agent
entry-point may invoke directly.
- The graph is validated at profile load time: every name must resolve
to a known command.
## from{caller} passthrough (replaces allow_commands)
Per-caller behaviour map on `CommandEntry`, keyed by calling command
name. `{ "action": "passthrough" }` bypasses intercept rules for that
caller, enabling credential chains (e.g. ddtool → curl) without
exposing raw tokens to the primary sandbox. Requires mutual consent:
if `curl.from["dd-auth"]` is set, `dd-auth.can_use` must contain
"curl". Validated at load.
## Binary identity pinning
Captures each mediated binary's dev/inode/size/mtime/sha256 at session
start (O_NOFOLLOW). Before every spawn, re-verifies the binary hasn't
been replaced. Fail-closed: a missing or mismatched pin blocks the exec.
Symlink fix: Homebrew installs binaries as symlinks under
/opt/homebrew/bin. O_NOFOLLOW returns ELOOP on symlinks. Both
pin_binary (session.rs) and verify_pin (policy.rs) now canonicalize the
path before opening.
## Dynamic token expansion
expand_profile_tokens_with previously only walked the legacy cmd.sandbox
field. Tokens in cmd.default.sandbox (the new DSL path) and per-intercept
sandboxes were never expanded, so @git:config-files had no effect.
Fixed by walking all three locations. New unit test covers the case.
## Regex: unicode-perl feature
The regex crate was configured without unicode-perl, so \s, \d, \w in
intercept match patterns failed at runtime. Added the feature and a
regression test.
23c1be5 to
bda3e68
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full redesign of nono's command mediation DSL and security model, implementing ETI gap-closure plans 1–4.
DSL changes
Explicit default block. Every
mediation.commandsentry now has adefaultwith anaction(allow/deny) and optionalsandbox. There is no implicit passthrough — unmatched invocations are governed by the default, which must be declared.Three action types (renamed from
run/respond):allow— execute the binary. Carries optionalscript.deny— return canned stdout/stderr/exit_code without running anything.capture— intercept credential-fetching commands, return a nonce, promote to a real token only when an authorised command requests it.deny_unknown_fieldson all eight mediation structs. Invalid profile fields are rejected at load time rather than silently ignored.Authorization graph —
can_use/session_can_useReplaces
caller_policy.session_can_useat the mediation root lists commands the agent entry-point may invoke directly;can_useon each command entry lists commands it may invoke as children. The graph is validated at profile load: every name must resolve to a known command.from{caller}passthroughReplaces
allow_commands. Per-caller behaviour map onCommandEntry, keyed by calling command name.{ "action": "passthrough" }bypasses intercept rules for that caller, enabling credential chains (e.g.ddtool → curl) without exposing raw tokens to the primary sandbox. Requires mutual consent at validation time.Binary identity pinning
Captures each mediated binary's dev/inode/size/mtime/sha256 at session start (
O_NOFOLLOW). Re-verifies before every spawn. Fail-closed: a missing or mismatched pin blocks the exec.Symlink fix: Homebrew installs binaries as symlinks under
/opt/homebrew/bin.O_NOFOLLOWreturnsELOOPon symlinks. Bothpin_binaryandverify_pinnow canonicalize the path before opening.Dynamic token expansion
expand_profile_tokens_withpreviously only walked the legacycmd.sandboxfield, so@git:config-filestokens incmd.default.sandbox(the new DSL path) were never expanded. Fixed by walkingcmd.default.sandboxand per-intercept sandboxes. New unit test covers this.Regex:
unicode-perlfeatureThe
regexcrate was configured withoutunicode-perl, so\s,\d,\win intercept match patterns failed at runtime when a profile was loaded. Added the feature and a regression test.