Constrain controlled CLI sessions and prove native budget overshoot
Some checks failed
Governed runtime contract / contract (push) Failing after 27s
Some checks failed
Governed runtime contract / contract (push) Failing after 27s
Assistant: codex Assistant-Model: gpt-5.6-luna Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
e0b3ff99a2
commit
4ae245a88f
14 changed files with 752 additions and 10 deletions
84
docs/evidence/2026-09-09-native-cli-overrun.json
Normal file
84
docs/evidence/2026-09-09-native-cli-overrun.json
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"case": "overrun",
|
||||
"binary_version": "2.1.266 (Claude Code)",
|
||||
"binary_sha256": "19842705e989393fce936804df6d2ab034860e24b8f8880357981d87ffd83fac",
|
||||
"argv": [
|
||||
"/opt/claude",
|
||||
"--print",
|
||||
"--permission-mode",
|
||||
"dontAsk",
|
||||
"--allowedTools",
|
||||
"Read,Write,Edit,Glob,Grep,Bash(git add:*),Bash(git commit:*),Bash(git status),Bash(git log:*),Bash(git diff:*),Bash(date:*),Bash(ls:*)",
|
||||
"--output-format",
|
||||
"json",
|
||||
"--max-budget-usd",
|
||||
"0.01",
|
||||
"--max-turns",
|
||||
"4",
|
||||
"--bare",
|
||||
"--setting-sources",
|
||||
"",
|
||||
"--strict-mcp-config",
|
||||
"--mcp-config",
|
||||
"{\"mcpServers\":{}}",
|
||||
"--disallowedTools",
|
||||
"mcp__*",
|
||||
"--tools",
|
||||
"Read,Write,Edit,Glob,Grep,Bash",
|
||||
"--no-session-persistence",
|
||||
"--model",
|
||||
"claude-sonnet-4-6"
|
||||
],
|
||||
"scope": "synthetic API in isolated network namespace; no real credential or provider request",
|
||||
"returncode": 1,
|
||||
"terminal": {
|
||||
"type": "result",
|
||||
"subtype": "error_max_budget_usd",
|
||||
"is_error": true,
|
||||
"total_cost_usd": 0.18015,
|
||||
"num_turns": 1,
|
||||
"usage": {
|
||||
"output_tokens_details": {
|
||||
"thinking_tokens": 0
|
||||
},
|
||||
"input_tokens": 0,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"server_tool_use": {
|
||||
"web_search_requests": 0,
|
||||
"web_fetch_requests": 0
|
||||
},
|
||||
"service_tier": "standard",
|
||||
"cache_creation": {
|
||||
"ephemeral_1h_input_tokens": 0,
|
||||
"ephemeral_5m_input_tokens": 0
|
||||
},
|
||||
"inference_geo": "",
|
||||
"iterations": [],
|
||||
"speed": "standard"
|
||||
},
|
||||
"permission_denials": []
|
||||
},
|
||||
"requests": [
|
||||
{
|
||||
"path": "/v1/messages?beta=true",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"max_tokens": 32000,
|
||||
"tools": [
|
||||
"Bash",
|
||||
"Edit",
|
||||
"Read"
|
||||
],
|
||||
"tool_results": [],
|
||||
"ambient_context_loaded": false
|
||||
}
|
||||
],
|
||||
"markers": {
|
||||
"hook-ran": false,
|
||||
"mcp-ran": false,
|
||||
"denied-ran": false
|
||||
},
|
||||
"created_file": null,
|
||||
"network_namespace": "net:[4026532321]"
|
||||
}
|
||||
118
docs/evidence/2026-09-09-native-cli-tools.json
Normal file
118
docs/evidence/2026-09-09-native-cli-tools.json
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
"case": "tools",
|
||||
"binary_version": "2.1.266 (Claude Code)",
|
||||
"binary_sha256": "19842705e989393fce936804df6d2ab034860e24b8f8880357981d87ffd83fac",
|
||||
"argv": [
|
||||
"/opt/claude",
|
||||
"--print",
|
||||
"--permission-mode",
|
||||
"dontAsk",
|
||||
"--allowedTools",
|
||||
"Read,Write,Edit,Glob,Grep,Bash(git add:*),Bash(git commit:*),Bash(git status),Bash(git log:*),Bash(git diff:*),Bash(date:*),Bash(ls:*)",
|
||||
"--output-format",
|
||||
"json",
|
||||
"--max-budget-usd",
|
||||
"1",
|
||||
"--max-turns",
|
||||
"4",
|
||||
"--bare",
|
||||
"--setting-sources",
|
||||
"",
|
||||
"--strict-mcp-config",
|
||||
"--mcp-config",
|
||||
"{\"mcpServers\":{}}",
|
||||
"--disallowedTools",
|
||||
"mcp__*",
|
||||
"--tools",
|
||||
"Read,Write,Edit,Glob,Grep,Bash",
|
||||
"--no-session-persistence",
|
||||
"--model",
|
||||
"claude-sonnet-4-6"
|
||||
],
|
||||
"scope": "synthetic API in isolated network namespace; no real credential or provider request",
|
||||
"returncode": 0,
|
||||
"terminal": {
|
||||
"type": "result",
|
||||
"subtype": "success",
|
||||
"is_error": false,
|
||||
"total_cost_usd": 0.0009000000000000001,
|
||||
"num_turns": 4,
|
||||
"usage": {
|
||||
"input_tokens": 200,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"output_tokens": 20,
|
||||
"output_tokens_details": {
|
||||
"thinking_tokens": 0
|
||||
},
|
||||
"server_tool_use": {
|
||||
"web_search_requests": 0,
|
||||
"web_fetch_requests": 0
|
||||
},
|
||||
"service_tier": "standard",
|
||||
"cache_creation": {
|
||||
"ephemeral_1h_input_tokens": 0,
|
||||
"ephemeral_5m_input_tokens": 0
|
||||
},
|
||||
"inference_geo": "",
|
||||
"iterations": [],
|
||||
"speed": "standard"
|
||||
},
|
||||
"permission_denials": [
|
||||
{
|
||||
"tool_name": "Bash",
|
||||
"tool_use_id": "tool_denied",
|
||||
"tool_input": {
|
||||
"command": "printf bypass > /work/denied-ran",
|
||||
"description": "Fixture forbidden operation"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"requests": [
|
||||
{
|
||||
"path": "/v1/messages?beta=true",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"max_tokens": 32000,
|
||||
"tools": [
|
||||
"Bash",
|
||||
"Edit",
|
||||
"Read"
|
||||
],
|
||||
"tool_results": [],
|
||||
"ambient_context_loaded": false
|
||||
},
|
||||
{
|
||||
"path": "/v1/messages?beta=true",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"max_tokens": 32000,
|
||||
"tools": [
|
||||
"Bash",
|
||||
"Edit",
|
||||
"Read"
|
||||
],
|
||||
"tool_results": [
|
||||
{
|
||||
"id": "tool_allowed",
|
||||
"is_error": false
|
||||
},
|
||||
{
|
||||
"id": "tool_create",
|
||||
"is_error": false
|
||||
},
|
||||
{
|
||||
"id": "tool_denied",
|
||||
"is_error": true
|
||||
}
|
||||
],
|
||||
"ambient_context_loaded": false
|
||||
}
|
||||
],
|
||||
"markers": {
|
||||
"hook-ran": false,
|
||||
"mcp-ran": false,
|
||||
"denied-ran": false
|
||||
},
|
||||
"created_file": "fixture-created\n",
|
||||
"network_namespace": "net:[4026532321]"
|
||||
}
|
||||
84
docs/native-cli-boundary-proof.md
Normal file
84
docs/native-cli-boundary-proof.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Native CLI boundary proof — 2026-09-09
|
||||
|
||||
The installed Claude Code 2.1.266 binary was exercised against a deterministic
|
||||
Anthropic-shaped API in a separate bwrap network namespace. The namespace had
|
||||
no provider network route, operator home, real credential or inference service.
|
||||
Only the CLI binary, system runtime and a temporary fixture workspace were mounted.
|
||||
The executable receipt records the binary SHA-256 and exact adapter-generated argv.
|
||||
|
||||
## Findings and resulting change
|
||||
|
||||
With `--max-budget-usd 0.01`, the first fixture response reported 60,000 input
|
||||
and 10 output tokens. The CLI estimated **USD 0.18015**, then exited with
|
||||
`error_max_budget_usd`. Only one messages request reached the fixture. This
|
||||
reproduces a stop after the response, not a pre-request maximum-liability check.
|
||||
The rein terminal-accounting validator refused success and preserved known cost.
|
||||
No amount in this experiment was billed by a provider.
|
||||
|
||||
The existing spend ledger remains necessary: it reserves declared per-run
|
||||
liability and retains unknown outcomes. The experiment does not establish that
|
||||
the declared liability is a valid bound on every possible native request. A
|
||||
provider-facing request guard is the next HFACT-WP-0001-T01 implementation return;
|
||||
raising the native threshold or accepting a newer binary cannot substitute for it.
|
||||
|
||||
The adapter also previously used `--allowedTools` with `acceptEdits`. Those flags
|
||||
alone did not constrain the available tool inventory or repository-provided
|
||||
customizations. Runs with native USD or turn controls now require CLI >=2.1.266
|
||||
and use `dontAsk`, explicit builtin tools derived from registered rules, `--bare`,
|
||||
empty settings sources, empty strict MCP configuration, an MCP deny rule, and no
|
||||
session persistence. Legacy unconfigured sessions retain their existing behavior.
|
||||
The worker prompt explicitly requires reading applicable AGENTS.md/CLAUDE.md;
|
||||
these files are instructions, not permission to load executable configuration or
|
||||
expand grants. The factory's protected runtime must be rebuilt and re-proven for
|
||||
the new minimum; this source change installs or admits no runtime.
|
||||
|
||||
The real binary's bare mode exposed Bash, Read and Edit, a subset of the explicit
|
||||
inventory. A synthetic tool sequence successfully ran permitted `git status` and
|
||||
created a new file through Edit. An unapproved shell write was denied. A fixture
|
||||
project containing a broad Bash permission override, a SessionStart hook and an
|
||||
MCP command could activate none of them; its ambient CLAUDE.md was not auto-loaded.
|
||||
The second messages request contained the expected allowed/denied tool results.
|
||||
|
||||
These tests prove the specified direct-tool and configuration boundaries. They
|
||||
are not an arbitrary-code sandbox proof: permitted Git operations can invoke
|
||||
repository-controlled helpers, and file edits can influence later commands.
|
||||
Filesystem, credential and network confinement remain sandbox-owner controls.
|
||||
To enforce spend against such indirect execution, the workload must not possess
|
||||
a provider credential plus an unmetered route to the provider. A run-scoped,
|
||||
owner-controlled request path must cover every forwarded request and retry.
|
||||
|
||||
## Reproduction and acceptance
|
||||
|
||||
`REIN_REAL_CLAUDE=1` enables `tests/test_native_cli_boundary.py`. The default binary
|
||||
comes from `claude` on PATH; `REIN_CLAUDE_PROOF_BINARY` can select an exact installed
|
||||
file. The fixture deliberately requires version 2.1.266; revalidate and record a
|
||||
new receipt before claiming the same proof for another version. The adapter's
|
||||
minimum-version gate does not itself prove arbitrary future binaries.
|
||||
|
||||
```text
|
||||
REIN_REAL_CLAUDE=1 REIN_REAL_BWRAP=1 python -m pytest tests/ -q
|
||||
```
|
||||
|
||||
The reproducible fixture is `tests/native_cli_fixture.py`; optional
|
||||
`REIN_CLAUDE_PROOF_OUTPUT` writes bounded evidence without prompts, headers,
|
||||
credentials or response bodies. The actual CLI checks are opt-in because ordinary
|
||||
CI does not provision that binary. Deterministic native launch/accounting tests
|
||||
are now included in both mandatory runtime and recovery gates. Paired receipts:
|
||||
`docs/evidence/2026-09-09-native-cli-overrun.json` and
|
||||
`docs/evidence/2026-09-09-native-cli-tools.json`.
|
||||
|
||||
No paid factory request, profile promotion, credential reader or production
|
||||
rollout was authorized or performed. REINAH-WP-0003-T05/T06 and HFACT-WP-0001-T01/
|
||||
T03/T04/T05 retain the request-admission, exact identity, protected placement and
|
||||
natural queue/model execution returns.
|
||||
|
||||
## Upstream contract reviewed
|
||||
|
||||
The [CLI reference](https://code.claude.com/docs/en/cli-reference) distinguishes
|
||||
available tools from auto-permission rules and describes the native stop flag.
|
||||
The [headless guide](https://code.claude.com/docs/en/headless) documents bare-mode
|
||||
configuration isolation and the API-key authentication path. The
|
||||
[cost guide](https://code.claude.com/docs/en/costs) identifies CLI totals as local
|
||||
estimates, not authoritative billing, and notes the residency-cost correction in
|
||||
2.1.239. Reviewed 2026-09-09; the local executable findings above are narrower
|
||||
than a claim about all provider billing or future CLI releases.
|
||||
|
|
@ -26,7 +26,7 @@ still requires the existing recovery process to classify the resulting commit.
|
|||
Glas profile limits `max_budget_usd` and `max_turns` are carried in its generated
|
||||
TaskSpec into the agentic Claude adapter. A supplied task file cannot bypass
|
||||
these profile controls. Positive finite USD amounts and positive integer turn
|
||||
limits are required. A controlled run verifies Claude Code >= 2.1.217, supplies
|
||||
limits are required. A controlled run verifies Claude Code >= 2.1.266, supplies
|
||||
`--max-budget-usd` / `--max-turns`, and requires one successful terminal JSON
|
||||
result with valid cost, turn and token accounting. Limit exhaustion, missing
|
||||
accounting and reported overruns cannot produce a successful run. Bounded USD
|
||||
|
|
@ -56,3 +56,9 @@ invalid/exhausted results and refusal of older CLI versions without inference.
|
|||
The subsequent [durable spend admission](spend-admission.md) return implements
|
||||
private daily/total reservation and unknown-outcome recovery in the worker.
|
||||
Provider liability/FX proof and final operating admission remain open.
|
||||
|
||||
The [installed CLI boundary proof](native-cli-boundary-proof.md) reproduces native
|
||||
budget overshoot and verifies controlled configuration/tool confinement. Native
|
||||
USD/turn-controlled runs now use bare mode and dontAsk with an explicit inventory;
|
||||
applicable repository instructions must be read as task context. The first paid
|
||||
factory run still requires a provider-facing request admission guard.
|
||||
|
|
|
|||
|
|
@ -131,3 +131,9 @@ or verify the operator's FX assumption. G0 remains blocked until those semantics
|
|||
are proven for the pinned provider/CLI, including retries, cache, subagents and
|
||||
in-flight work. Exact credential/identity/egress/placement and protected-runtime
|
||||
installation are also still required before natural factory execution.
|
||||
|
||||
The [native CLI proof](native-cli-boundary-proof.md) now demonstrates the missing
|
||||
pre-request bound: one fixture response overshot a USD 0.01 threshold to an
|
||||
estimated USD 0.18015. HFACT T01 must implement and prove a metered request path
|
||||
outside the workload, including direct-provider bypass denial. The full-charge
|
||||
reservation/reconciliation implementation remains unchanged.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue