8000 feat(minimal): read client-owned store rules and refuse rules in the deny set by minimal-foundry[bot] · Pull Request #2514 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(minimal): read client-owned store rules and refuse rules in the deny set - #2514

Merged
norrietaylor merged 14 commits into
mainfrom
agent/2280-read-client-owned-store-rules-and-refuse-rules-i
Oct 24, 2026
Merged

norrietaylor merged 14 commits into
mainfrom
agent/2280-read-client-owned-store-rules-and-refuse-rules-i

Conversation

@minimal-foundry
@minimal-foundry minimal-foundry Bot commented Oct 24, 2026 •
Copy link
Copy Markdown
Contributor

T25 — Read client-owned store rules and refuse rules in the deny set

slice: S3
kind: task
covers: BEP-034, BEP-035, BEP-036, BEP-037
size: L
est: 350 code, 300 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: a refused rule prints "The secret-store rule in names , which a secret can never be sent to. Remove or change the rule." on stderr when the configuration is read, pinned by store_rule_in_deny_set_is_refused
observability: one debug log line per configuration read naming each rule refused and why
layers:
- config:
- crates/minimal/src/config.rs: reads [secret-store-rules] from the client configuration
- crates/boxes/src/core/bep.rs: the BEP-034, BEP-035 and BEP-036 refusals
- crates/mfile/src/lib.rs: ignores a project's [secret-store-rules] with a warning
test: cargo nextest run -p boxes store_rule_in_deny_set_is_refused
test: cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused
test: cargo nextest run -p boxes ask_rule_without_tty_denies
test: cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3
test: cargo nextest run -p boxes project_store_rules_are_ignored_with_warning
produces: none
consumes: none
proof: A store rule aimed at a GitHub host or the Host header is refused by name when the configuration is read.
depends on:
- blocked by #2276

Proof

A person can put a [secret-store-rules.] rule in their config.toml. If the rule's upstream is a GitHub host (for example api.github.com) or its header is Host, any min command that reads the client configuration prints "The secret-store rule in names api.github.com, which a secret can never be sent to. Remove or change the rule." on stderr (for a header, "names the header Host"), and leaves that rule out.

Notes from the agent: Rule shape (the spec does not fix it): [secret-store-rules.] with the table key as the item identifier and the rule name, and the fields store (optional, None = the host's native store), upstream, header + optional prefix or basic_auth, and action = allow|ask|deny (optional). The spec names only "ask". allow and deny are my additions. A rule with no upstream, or with not exactly one injection form, is refused too, with its own message. Store references: the tree has no source = "store". Existing code and tests treat a non-github: scope on a broker grant (<store>:<id>, for example keychain:npm) as a store reference, so StoreReference follows that convention and no GrantSource variant was added. Adding one would also need create.rs, which is out of scope. Minimal's own infrastructure is the domain minimal.dev and its subdomains (MINIMAL_INFRASTRUCTURE). Extend it if Gatehouse or other hosts belong there. The GitHub sign-in item identifiers come from bep::signin::SERVICE and META_SERVICE, through StoreDenySet, because boxes does not depend on bep. Wiring still owed by later tasks: check_store_references (BEP-034 reference half, BEP-036 exit 3) and store_consent (BEP-035) are pure functions with tests, but no create or expansion path calls them yet, because create.rs and the expansion code are not in this task's layers. read_client_config_and_store_rules returns the accepted rules, and nothing consumes them yet (the bep crate still reads no rules). read_client_config now prints refusals on each read. A command th…[truncated]

Tests

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-5e71... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-02ba... Finished 'test' profile [unoptimized] target(s) in 0.76s ──────────── Nextest run ID f1c7c27a-273d-4fcc-8b9c-95e90c4a7aa0 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-2ef7... Finished 'test' profile [unoptimized] target(s) in 0.69s ──────────── Nextest run ID 82b825b0-7407-477e-aa6a-8842c4dac852 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-e7e8... Finished 'test' profile [unoptimized] target(s) in 0.84s ──────────── Nextest run ID 3f968ef6-d8ae-4925-ba12-1e20273d51fb with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-3fe3... Finished 'test' profile [unoptimized] target(s) in 0.71s ──────────── Nextest run ID 1d4903e5-02a9-4078-9b9f-64e2f71465cd with nextest profile: default Starting 1 test across 3

Verify

min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-e4dd...
    Checking args v0.0.1 (/workbench/crates/args)
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking wait-timeout v0.2.1
    Checking rusty-fork v0.3.1
    Checking proptest v1.12.0
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Residuals

  • #2516: call check_store_references (BEP-034 reference half, BEP-036 exit 3) and store_consent (BEP-035) from box creation and expansion, and hand the accepted rules to the proxy's registration (arch C3 at 0a302e1, C7 at 8752a66). This PR adds the checks as pure functions; only the config-read deny-set refusal runs today.
  • #2441: the infrastructure deny set passed from config.rs is bep::ca::DENY_SET, which holds min.internal and minimal.dev only; Gatehouse §6.10 line 849 also names the tenant issuer, the BEP, EGW and relay endpoints and the node-plane baseline set, and Decide and share the fixed deny set for the box CA name constraints (BEP-013, BEP-034) #2441 owes those names (arch C1 at 0a54305).

Closes #2280


Generated by Claude Code

Add the [secret-store-rules] rule type and its checks: a rule naming a
GitHub host, Minimal's own infrastructure, a denied injection header or
the GitHub sign-in item is refused by name (BEP-034). An ask rule denies
without a terminal (BEP-035). A store reference whose registered upstream
the egress does not admit refuses with exit 3 (BEP-036). A project table
is ignored with a warning (BEP-037).
Only the user's own config.toml can set secret-store rules (BEP-037).
The table, at the top level or under [session], now gets its own
warning in place of the generic unknown-field one.
config.toml now accepts the table. Reading the config refuses each rule
the deny set covers, prints it by name on stderr, and leaves it out of
the rules it returns (BEP-034).
@coderabbitai
coderabbitai Bot commented Oct 24, 2026 •
Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5d8bb450-fb84-41c9-b30b-929fc50cefee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@minimal-foundry
minimal-foundry Bot commented Oct 24, 2026 • 8000
Copy link
Copy Markdown
Contributor Author

Reviewed: no findings; approval withheld, 3 threads unresolved at 97cf1be249de.

APPROVE withheld: 3 unresolved threads — minimal-foundry[bot] crates/boxes/src/core/bep.rs:1104, minimal-arch[bot] crates/minimal/src/config.rs:219, minimal-arch[bot] crates/boxes/src/core/bep.rs:1276. Resolving the last thread releases the approval on this head.

Resolve the open threads. Resolving the last one releases the approval on this head; no new review is required.

Verdict APPROVE, posted as a comment: the App cannot review its own pull request; the check and the label carry it.

Clobber: none seen.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 4 findings, 4 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
8000
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: CONDITIONS · 3 conditions · the full ruling

The deny set for store rules is incomplete. MINIMAL_INFRASTRUCTURE is a second list, and it leaves out min.internal, so a rule aimed at host.min.internal is accepted. Gatehouse §6.10 line 849 says no upstream can name the BEP endpoints. C1 makes the check read bep::ca::DENY_SET. Line 849 also says a rule registers exact authorities with no patterns. C2 refuses *.example.com and the like. BEP-035 and BEP-036 are pure functions that no path calls. C3 asks for a filed issue for each piece of the deferred wiring. The TOML shape of a rule is an escalation, not a condition.

Ruled at 0a302e1 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
An upstream with userinfo, a path, brackets, a wildcard or whitespace
named a host the deny set did not see. A header that is not an HTTP
token, or a prefix with a control character, could inject a header line.
Refuse each as a malformed field, by name.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 1 of 10 on the runtime's review findings, pushed as 8752a66306f0.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-74a3... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-7d3a... Finished 'test' profile [unoptimized] target(s) in 0.49s ──────────── Nextest run ID 4344aa7f-3c97-45ac-88e6-827ce17bdd35 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-ea05... Finished 'test' profile [unoptimized] target(s) in 0.60s ──────────── Nextest run ID 4cab9b87-32c1-44a0-aaf3-19cb1e4d357b with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-4531... Finished 'test' profile [unoptimized] target(s) in 0.68s ──────────── Nextest run ID 6f7f61af-80ec-45fb-b77b-c22e7d9475dd with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-5d1e... Finished 'test' profile [unoptimized] target(s) in 0.60s ──────────── Nextest run ID b6dcd8f9-3289-409b-aa3a-d1e3846de92a with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

ph)
   Compiling darling v0.24.0
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking strum v0.28.0
    Checking sha3 v0.11.0
    Checking p521 v0.14.0
    Checking p384 v0.14.0
    Checking unicode-truncate v2.0.1
    Checking opentelemetry-appender-tracing v0.33.1
    Checking kasuari v0.4.12
    Checking hash32 v0.3.1
    Checking module-lattice v0.2.3
    Checking lru v0.18.2
    Checking kem v0.3.0
    Checking data-encoding v2.11.1
    Checking sponge-cursor v0.1.0
    Checking size v0.5.0
   Compiling litrs v1.0.0
   Compiling smoltcp v0.14.0
    Checking compression-core v0.4.33
    Checking compression-codecs v0.4.45
   Compiling document-features v0.2.12
    Checking sha3 v0.12.0
    Checking ml-kem v0.3.2
    Checking ratatui-core v0.1.2
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking ssh-key v0.7.0-rc.11
    Checking signal-hook-mio v0.2.5
    Checking generic-array v1.4.4
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking derive_more v2.1.1
    Checking russh-cryptovec v0.62.0
   Compiling enum_dispatch v0.3.13
    Checking num-bigint v0.5.1
    Checking russh-util v0.52.0
    Checking rcache v0.0.1 (/workbench/crates/rcache)
   Compiling ring v0.17.14
   Compiling delegate v0.13.5
    Checking managed v0.8.0
    Checking tinyvec_macros v0.1.1
    Checking constcat v0.6.1
    Checking hex-literal v1.1.0
    Checking tagptr v0.2.0
    Checking bitflags v1.3.2
    Checking moka v0.12.16
    Checking russh v0.64.1
    Checking op v0.0.1 (/workbench/crates/op)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking tinyvec v1.12.0
    Checking crossterm v0.29.0
    Checking async-compression v0.4.50
    Checking async-tar v0.6.1
    Checking getrandom v0.2.17
    Checking line-clipping v0.3.8
    Checking object v0.40.0
    Checking is_executable v1.0.6
    Checking clap_complete v4.6.11
    Checking check v0.0.1 (/workbench/crates/check)
    Checking orchestrator v0.0.1 (/workbench/crates/orchestrator)
    Checking ratatui-widgets v0.3.2
    Checking hickory-proto v0.26.3
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

  • 👍 valid — crates/boxes/src/core/bep.rs:1292: Added is_plain_authority. An upstream with @, /, brackets, a wildcard, whitespace, an empty host or a bad port is now refused as StoreRuleRefusal::Malformed (field upstream), before the deny-set check. Pinned in store_rule_in_deny_set_is_refused_when_malformed.
  • 👎 invalid — crates/minimal/src/config.rs:33: Dropping the rules is on purpose in this task. Their consumer is box-spec expansion in crates/minimal/src/cmd/boxes/create.rs, which is outside this task's layers. No command reads the config twice: create.rs:909 reads it once per box creation, and loadouts.rs:564 is in cmd_loadout_list, a different
  • 👍 valid — crates/boxes/src/core/bep.rs:1088: Added is_http_token (RFC 9110 tchar) for the header, after the deny-set check, and a visible-ASCII/space/tab check for the prefix. X-A\r\nHost: evil, Host: and a CRLF prefix are now refused as Malformed. Pinned in store_rule_in_deny_set_is_refused_when_malformed.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1282: To call check_store_references and store_consent, the code must change crates/minimal/src/cmd/boxes/create.rs. That file is outside this task's layers (config.rs, bep.rs, mfile/src/lib.rs). result.json notes say a later task must connect them, and that until then only the config-read deny-set refusa

When a min command reads the client config.toml, a [secret-store-rules] rule aimed at a GitHub host or the Host header prints a refusal on stderr that names the rule and the file. The rule is then left out. A rule with an upstream such as x@api.github.com or *.github.com, or a header or prefix that contains CR or LF, is now refused by name too.

Notes from the agent: This round adds StoreRuleRefusal::Malformed. It refuses an upstream that is not a plain host or host:port, a header that is not an HTTP token, and a prefix with a control character. The new message is mine because the task fixes no wording for it: "The secret-store rule in has the "", which is not . Change the rule." No part of this task calls check_store_references, store_consent or store_refusals in a real command. To connect them, box creation in crates/minimal/src/cmd/boxes/create.rs (near line 909) must call read_client_config_and_store_rules and pass the rules to expansion. That file is outside this task's layers, so a later task must make that change. Until then, the only enforcement that runs is the deny-set refusal at config read. I did not run just clippy-strict.

8000

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 3 findings, 3 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: CONDITIONS · 7 conditions · the full ruling

This head adds only the malformed-field refusals, and those conform. The rest of the earlier findings stay open. The rules table breaks the attach path, because Config refuses unknown fields (C1). The rule shape is not the design's {store, id_glob, upstream, inject, action} array (C2). A rule with no action allows, but the design default is ask (C3). The deny set admits host.min.internal, the BEP address (C4). C5 to C7 cover the unmatched reference, the org file and the unfiled wiring residual.

Ruled at 8752a66 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
The store-rule check now takes bep::ca::DENY_SET from the client, so
host.min.internal is refused. An upstream that is an IP address, has an
empty label or has a port outside 1-65535 is refused as malformed.
The client prints each refused rule once per process.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 2 of 10 on the runtime's review findings, pushed as 56abd893c7fe.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-47eb... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-17ad... Finished 'test' profile [unoptimized] target(s) in 0.30s ──────────── Nextest run ID 47908cb0-f32c-4a46-a445-232d4fcc3cc6 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-6e88... Finished 'test' profile [unoptimized] target(s) in 0.34s ──────────── Nextest run ID 655e6212-38dc-476e-b4f6-cb2b7f1534eb with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-9701... Finished 'test' profile [unoptimized] target(s) in 0.39s ──────────── Nextest run ID c81cafe3-7bee-4f75-a13b-aec7eda2153a with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-2267... Finished 'test' profile [unoptimized] target(s) in 0.35s ──────────── Nextest run ID 179c193f-b379-4d02-88c3-d3d30993b126 with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-5001...
    Checking args v0.0.1 (/workbench/crates/args)
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

  • 👍 valid — crates/boxes/src/core/bep.rs: Removed MINIMAL_INFRASTRUCTURE. StoreDenySet has a new infrastructure field, and the client fills it with bep::ca::DENY_SET, so host.min.internal is refused. A test pins it.
  • 👍 valid — crates/minimal/src/config.rs:99: refuse_store_rules now passes infrastructure: bep::ca::DENY_SET beside the module hosts. The config test checks that host.min.internal is refused by name.
  • 👍 valid — crates/boxes/src/core/bep.rs:1043: The last round added is_plain_authority, which refuses *, /, @, whitespace, a scheme and an empty host, and names the entry. This round adds three refusals: an empty label, a port of 0 or above 65535, and an IP address.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1265: It is true that no path calls these functions yet. The calls belong in the box create path, which is outside this task's layers (config.rs, bep.rs, mfile). This run cannot file issues, so the result notes record both calls as residuals, and a person must file them.
  • 👍 valid — crates/boxes/src/core/bep.rs:1314: is_plain_authority now refuses a host whose last label is decimal digits or 0x hex, which is how a URL parser reads IPv4. 140.82.112.5, 2354212869 and 0x8c527005 are refused. A colon form such as IPv6 was already refused.
  • 👍 valid — crates/minimal/src/config.rs:33: read_client_config_and_store_rules prints the refusals only on the first read in a process. Later reads still drop the refused rules but write nothing. Each refusal prints once per command.
  • 👎 invalid — crates/boxes/src/core/bep.rs:858: BEP-034 fixes the denied headers as Host, :authority, Cookie, Proxy-*, Transfer-Encoding, Connection and Upgrade. A longer list changes the spec. The secret only goes to the exact upstream that the rule registers. The proxy's framing rule rejects a request with conflicting Content-Length and Transfe

When min reads config.toml, it refuses a [secret-store-rules] rule aimed at a GitHub host such as api.github.com, at the Host header, or at host.min.internal or minimal.dev. It names the rule and the file on stderr once per command, and leaves the rule out. An upstream written as an IP address is refused too.

Notes from the agent: Revise round 2. The infrastructure names now come from bep::ca::DENY_SET, through the new StoreDenySet::infrastructure field. MINIMAL_INFRASTRUCTURE is removed. Residuals for the PR body: no expansion path calls check_store_references (BEP-036, and the reference half of BEP-034), and no path calls store_consent (BEP-035). These calls belong in the box create path, which is outside this task's layers. I cannot file issues from this box, so a person must file them. clippy for -p boxes -p minimal printed warnings only in minimald and minimald-rpc. I did not change those crates.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 4 findings, 4 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: CONDITIONS · 2 conditions · the full ruling

The deny set now covers host.min.internal and refuses IP-address upstreams. This closes the earlier points. Two items stay open. store_refusals lets a store reference with no rule through, but Gatehouse §6.10 line 849 gates every store reference by a rule. Refuse that reference (C1). No code calls check_store_references or store_consent yet, and the PR body names no issue for that wiring. Link one (C2).

Ruled at 56abd89 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
…rsing

Config now carries [secret-store-rules], so the attach reader parses a
config.toml that holds rules. The client reads the rules of the
organization config too and names that file in its refusals. Refusals
print once per file in a process.
A rule upstream such as gist.github.com is refused as a GitHub host,
as the infrastructure check already does for its names.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 3 of 10 on the runtime's review findings, pushed as 0a5430592e0b.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-4310... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-bc9c... Finished 'test' profile [unoptimized] target(s) in 0.34s ──────────── Nextest run ID 85dc229c-595d-4ed0-bab4-47f391c51df7 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-09ce... Finished 'test' profile [unoptimized] target(s) in 0.33s ──────────── Nextest run ID 6a043812-d0a3-4c08-8de6-0d431c25fe9b with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-fb9b... Finished 'test' profile [unoptimized] target(s) in 0.33s ──────────── Nextest run ID d305f617-ff4e-4ea8-989f-4270d57176bb with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-e1f3... Finished 'test' profile [unoptimized] target(s) in 0.33s ──────────── Nextest run ID 6c452068-7481-46b9-8d64-2f2a164264c9 with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-8cb2...
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking args v0.0.1 (/workbench/crates/args)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Outside the task's layers::

  • crates/boxes/src/client/config.rs

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — crates/minimal/src/config.rs: Added secret_store_rules (renamed secret-store-rules) to boxes::client::config::Config, so read_config_or_default parses a file with rules. read_config_parts now takes the rules out of Config. Pinned by store_rules_parse_through_attach_reader.
  • 👎 invalid — crates/boxes/src/core/bep.rs:876: This task's spec binds the shape: BEP-079 writes the rule for with --upstream, --header, an optional --prefix, or --basic-auth, and no consent action. The rule is keyed by item id and store is optional (the native store). No id_glob or nested inject is in the covered requirements. Reconciling w
  • 👎 invalid — crates/boxes/src/core/bep.rs:1204: The spec excerpt has no action_for_unspecified. BEP-079 writes rules with no consent action, and BEP-052 lists a rule's consent as the rule or none. BEP-035 denies only a rule with action = "ask". Defaulting to ask makes every rule that min secret set writes deny without a TTY.
  • 👎 invalid — crates/boxes/src/core/bep.rs: Already so on this branch. The infrastructure list is bep::ca::DENY_SET, which holds min.internal, so host.min.internal is refused (store_rules_read_through_client_config pins it). is_plain_authority refuses every IPv4 literal (numeric last label, decimal or hex) and every bracketed IPv6 literal, so
  • 👎 invalid — crates/boxes/src/core/bep.rs:1240: BEP-036's property is: expansion refuses iff some registered upstream is absent from egress. A reference with no matching rule registers no upstream, so refusing it here breaks that iff. Such a reference is unredeemable at the proxy (BEP-064: no current rule), and no covered requirement refuses it a
  • 👍 valid — crates/minimal/src/config.rs: read_client_config_and_store_rules now also reads [secret-store-rules] from ORGANIZATION_CONFIG_PATH and names that file in its refusals. A user rule replaces an organization rule for the same item.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1266: The wiring needs crates/minimal/src/cmd/boxes/create.rs, which is outside this task's layers, and this session has no credential to file an issue. The residual is stated in the result notes, for the PR body: no create or expansion path calls check_store_references or store_consent yet.
  • 👍 valid — crates/boxes/src/core/bep.rs: Module hosts now match the host or any name under it, as the infrastructure check does (shared is_within). gist.github.com, www.github.com and x.api.github.com are refused, pinned by store_rule_in_deny_set_is_refused_under_module_host.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1286: This task's layers stop at the config reader and bep.rs, and its produces line is none. Wiring into box creation needs crates/minimal/src/cmd/boxes/create.rs, outside the layers. The result notes state that a later task owns the call sites.
  • 👍 valid — crates/minimal/src/config.rs:34: The once-per-process flag is now a set of paths, so each file's refusals print on its first read. The org file is now read too. The accepted rules have no consumer yet, because the call sites are outside this task's layers.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1271: Same as the other wiring threads: spec expansion lives in crates/minimal/src/cmd/boxes/create.rs, outside this task's layers. The result notes state that a later task wires check_store_references in.

A store rule in the user or the organization config.toml that is aimed at a GitHub host (or a name under one, such as gist.github.com) or at the Host header is refused by name on stderr when the configuration is read. The attach path still parses a config.toml that holds rules.

Notes from the agent: Out of layers: crates/boxes/src/client/config.rs. Config now has a secret_store_rules field (serde rename secret-store-rules). Without it, the attach reader (read_config_or_default, deny_unknown_fields) fails on any config.toml that holds a rule (thread C1). No layer file can fix that. Organization rules are read from ORGANIZATION_CONFIG_PATH. A user rule replaces an organization rule for the same item. This precedence is my choice, and the spec does not set it. Still not done, and a later task owns it: no create or expansion path calls check_store_references or store_consent. That wiring needs crates/minimal/src/cmd/boxes/create.rs, which is outside this task's layers. I have no credential to file an issue for it, so the PR body or a person must record it as a residual. The rule shape (flat header/prefix/basic_auth, keyed by item id, optional store) and the default of no consent action are unchanged. They follow BEP-079 and BEP-052 in this task's spec excerpt, not the Gatehouse shape that threads C2 and C3 cite. cargo fmt ran after the test runs and changed only formatting. The task proof says when the configuration is read: the refusal prints when a command reads config.toml through read_client_config.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft October 24, 2026 05:50
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling

The store-rule read and refusal conform to Gatehouse §6.10 line 849. This head fixes the open items from the last round: it reads the org config, keeps the attach parser working and refuses names under a module host. One gap is left. The deny set holds only min.internal and minimal.dev, but line 849 also names the tenant issuer, the relay endpoints and the node-plane baseline set. Issue #2441 tracks that gap, but the PR body does not name it. Add it to the Residuals section, as C1 says.

Ruled at 0a54305 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 4 of 10 on a failed check suite: the coder changed nothing. Revise round 4. No code change in this round. CI: the cargo-deny failure is a new RUSTSEC advisory (timing variability) in ecdsa/primeorder/rfc6979, pulled in by russh 0.64.1, plus an unused RUSTSEC-2026-0009 ignore in deny.toml. This branch does not change Cargo.lock or deny.toml. The fix is a dependency bump or a deny.toml change, which is outside this task's layers. ci-success fails only because cargo-deny fails. For the PR body: under 'Wiring still owed by later tasks', no expansion path calls check_store_references or store_refusals, and no consent path calls store_consent. This session cannot file an issue, so a person must file one for that wiring and link it there. Under 'Residuals', name #2441: config.rs passes bep::ca::DENY_SET (min.internal, minimal.dev) as the infrastructure deny set. Gatehouse also names the tenant issuer, the BEP/EGW/relay endpoints and the node-plane baseline set, and #2441 owes those.

Review threads the coder judged:

  • 👎 invalid — crates/boxes/src/core/bep.rs:1241: The covered requirement BEP-036 refuses expansion if and only if a registered upstream is absent from egress. A reference with no rule registers no upstream, so refusing it here breaks that property. prop_store_upstream_outside_egress_is_exit_3 pins this. A gate for references with no rule is a Gate

@norrietaylor
norrietaylor marked this pull request as ready for review October 24, 2026 06:09
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 2 findings, 2 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review at 0a54305.

Four files, all in the task's config layer as #2280 now reads (crates/boxes/src/client/config.rs was added for arch C1). bep.rs holds the rule type, the deny set, the refusals and their messages, plus the pure check_store_references and store_consent; config.rs reads the user and organization files, takes the rules out of Config and prints each refusal once per file per process; mfile ignores a project's table with the BEP-037 warning; the client Config type now parses a file that holds rules.

Checked against the diff:

  • The deny set is one list: GitHub's module hosts and bep::ca::DENY_SET, both matched by exact name or any name under it. Sign-in item identifiers come from bep::signin.
  • A rule reaches the name compare only as a plain host or host:port: userinfo, paths, brackets, wildcards, whitespace, an empty host, IP literals (decimal and hex last label) and ports outside 1 to 65535 are refused as malformed and named back as written. Headers must be RFC 9110 tokens and prefixes visible ASCII, so no CRLF injection passes.
  • Every refusal states the rule, its file and one action, in the task's fixed words; store_rules_read_through_client_config pins the stderr text for three refusals.
  • The organization file is read, a user rule wins for the same item, and a second read in one process prints nothing.
  • store_consent denies an ask rule without a terminal (BEP-035); prop_store_upstream_outside_egress_is_exit_3 pins BEP-036's exit 3 exactly when a registered host is outside the egress.

Not in this PR, by design and filed: no creation or expansion path calls check_store_references or store_consent yet (#2516), and the names Gatehouse lists beyond bep::ca::DENY_SET are #2441's. Both sit in the Residuals section.

No findings. Arch PASS_WITH_CONDITIONS stands at 0a54305 with its one condition met in the body.


Generated by Claude Code

A user rule replaces the fields of an organization rule for the same
item but never loosens its deny or ask. Commands that use no store
rules no longer fail on an organization file that does not parse.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 5 of 10 on the runtime's review findings, pushed as ae74c8d37519.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-6cab... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-4c1e... Finished 'test' profile [unoptimized] target(s) in 0.50s ──────────── Nextest run ID b633eded-8b33-4c3d-a974-2b39d3c4cad1 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-f582... Finished 'test' profile [unoptimized] target(s) in 0.55s ──────────── Nextest run ID 965a31a2-c957-4c71-b196-27ef6ef7e161 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-1bf0... Finished 'test' profile [unoptimized] target(s) in 0.54s ──────────── Nextest run ID 4a056565-32f9-4ee5-908a-9d3badb021cd with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-e903... Finished 'test' profile [unoptimized] target(s) in 0.63s ──────────── Nextest run ID d82dbb55-e22b-4ba8-9d87-f605b39a744c with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-296c...
    Checking args v0.0.1 (/workbench/crates/args)
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking wait-timeout v0.2.1
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking quick-error v1.2.3
    Checking bit-vec v0.10.1
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking bit-set v0.11.1
    Checking rusty-fork v0.3.1
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking rand_xorshift v0.5.0
    Checking unarray v0.1.4
    Checking core_detect v1.0.0
    Checking proptest v1.12.0
    Checking lcache v0.0.1 (/workbench/crates/lcache)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

  • 👍 valid — crates/minimal/src/config.rs: Added merge_store_rules: a user rule replaces an organization rule's fields but keeps the stricter action (deny > ask > allow/none). The test user_store_rule_keeps_stricter_org_action covers it.
  • 👍 valid — crates/minimal/src/config.rs: read_client_config now treats an organization file that does not read or parse as non-fatal. It prints the error once on stderr and drops that file's rules. read_client_config_and_store_rules still fails on that file.

A store rule in the client configuration that names a GitHub host or the Host header is refused by name on stderr when the configuration is read. A user rule can no longer loosen an organization deny or ask. A broken /etc/minimal/config.toml no longer fails min ls, create, task or loadout resolution.

Notes from the agent: Round 5 changed only crates/minimal/src/config.rs. read_client_config, which list, create, task and loadouts use, now treats an organization file that is not read or does not parse as non-fatal. It prints one stderr line, logs one debug line and leaves out the organization rules. read_client_config_and_store_rules, for callers that use rules, still fails on that file. New printed text: "Minimal did not use /etc/minimal/config.toml. . The secret-store rules in that file do not apply to this command."

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

This push changes one doc comment and one stderr message in crates/minimal/src/config.rs. Neither change affects the store-rule checks that the ruling on ae74c8d3 covered, so that ruling stands. The doc comment is correct: read_client_config_and_store_rules fails closed on an unusable organization file. The wiring in #2516 must use that reader. Two conditions stay open as filed residuals. C1 (#2516) calls the consent and egress checks from box creation and expansion. C2 (#2441) adds the remaining infrastructure names that Gatehouse §6.10 line 849 lists.

Ruled at eb10c0e against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 2 findings, 2 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Revise round 4 ran against ci-success, cargo-deny and left it red; a coder round cannot clear it, a person should look. No round was started for the failed suite on eb10c0e37787.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 7 of 10 on the runtime's review findings, pushed as e9c8c13be401.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-2bed... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-3d1e... Finished 'test' profile [unoptimized] target(s) in 0.36s ──────────── Nextest run ID 1fe7fde2-ad60-470f-8c59-87a0b4a203ed with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-c3ba... Finished 'test' profile [unoptimized] target(s) in 0.31s ──────────── Nextest run ID a5bf109d-ba15-4300-8071-7b8a26fc01f5 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-2a1a... Finished 'test' profile [unoptimized] target(s) in 0.31s ──────────── Nextest run ID 6983b62a-5451-440f-9b45-d354504a2454 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-a5d9... Finished 'test' profile [unoptimized] target(s) in 0.33s ──────────── Nextest run ID 4a433c1c-1d6b-4234-bb5e-2eb60cccce38 with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-ea3d...
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking args v0.0.1 (/workbench/crates/args)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking wait-timeout v0.2.1
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking quick-error v1.2.3
    Checking bit-vec v0.10.1
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking bit-set v0.11.1
    Checking rusty-fork v0.3.1
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking rand_xorshift v0.5.0
    Checking unarray v0.1.4
    Checking core_detect v1.0.0
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking proptest v1.12.0
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking op v0.0.1 (/workbench/crates/op)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

A secret-store rule in the user or organization client configuration that names a GitHub host or the Host header is refused by name on stderr when the configuration is read, and it is left out of the rules. A refused organization rule still keeps its deny or ask action over a user rule for the same item.

Notes from the agent: This round changed one file: crates/minimal/src/config.rs. The organization rules as read, before refusal, now set the action floor after the merge, through keep_org_actions. The new test refused_org_rule_keeps_its_action_over_user_rule pins this (cargo nextest run -p minimal refused_org_rule: 1 passed). The other store_rule tests in the minimal crate also pass. Threads C1 and C2 from minimal-arch and the MEDIUM wiring finding repeat findings that earlier rounds answered. Issues #2441 and #2516 own that work, and it is outside this task's layers. I did not run just clippy-strict.

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

The compare keeps the action of an org store rule as a floor, also when the deny set refuses that rule. A user rule can no longer loosen an org deny or ask that way. Gatehouse §6.10 line 849 says nothing on the org and user merge, and this change is fail closed. The two baseline conditions stay open as filed residuals: C1 (#2516) and C2 (#2441).

Ruled at e9c8c13 against gominimal/arch@109541a48c31 by claude-opus-5-5.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 3 findings, 3 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/minimal/src/config.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 8 of 10 on the runtime's review findings, pushed as 959d87836c4b.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-61f5... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-4c65... Finished 'test' profile [unoptimized] target(s) in 0.65s ──────────── Nextest run ID 726042fa-edf5-425b-9bd8-f06b0f5a9136 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-4005... Finished 'test' profile [unoptimized] target(s) in 0.62s ──────────── Nextest run ID 21613b07-659b-4f46-93a8-e151e6da9540 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-9d31... Finished 'test' profile [unoptimized] target(s) in 0.66s ──────────── Nextest run ID f132495a-c6db-4d61-9ab8-b3be6aa6039b with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-149b... Finished 'test' profile [unoptimized] target(s) in 0.64s ──────────── Nextest run ID 87973875-b8f1-4a25-b733-065066238506 with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-8fca...
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking args v0.0.1 (/workbench/crates/args)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking common v0.0.1 (/workbench/crates/common)
    Checking switch v0.0.1 (/workbench/crates/switch)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking wait-timeout v0.2.1
    Checking bit-vec v0.10.1
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking quick-error v1.2.3
    Checking rusty-fork v0.3.1
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking bit-set v0.11.1
    Checking rand_xorshift v0.5.0
    Checking core_detect v1.0.0
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking unarray v0.1.4
    Checking proptest v1.12.0
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking op v0.0.1 (/workbench/crates/op)
    Checking check v0.0.1 (/workbench/crates/check)
    Checking orchestrator v0.0.1 (/workbench/crates/orchestrator)
    Checking mctx v0.0.1 (/workbench/crates/mctx)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

  • 👍 valid — crates/minimal/src/config.rs: read_client_and_org_config now adds a deny rule with no upstream or header for each item that has only refused rules, and a refused user rule keeps its stricter action (keep_read_actions runs on both files). Pinned by refused_only_item_is_denied.
  • 👎 invalid — crates/boxes/src/core/bep.rs:1290: To wire these checks into box creation, this PR must change crates/minimal/src/cmd/boxes/create.rs and the box spec expansion code. Those files are outside this task's layers (config.rs, bep.rs, mfile, client config). This task delivers the checks and the reader, and its tests pin them. A later task
  • 👎 invalid — crates/minimal/src/config.rs:79: read_client_config returns only the Config (read_client_and_org_config(global, false)?.0) and gives its caller no rules. The strict reader read_client_config_and_store_rules is already the only reader that returns rules. To wire it into create.rs, this PR must change a file outside its layers.

A store rule in the client configuration that names a GitHub host or the Host header is refused by name on stderr when the configuration is read. Its item no longer loses consent: the reader returns a deny rule for an item that has only refused rules.

Notes from the agent: Revise round 8. I ran the five boxes test lines as one nextest invocation with five filters, not as five separate runs. The wiring of store_refusals, check_store_references and read_client_config_and_store_rules into box creation is still outside this task's layers. crates/minimal/src/cmd/boxes/create.rs and the box spec expansion code are not in layers. A later task must call them.

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

The compare conforms to Gatehouse §6.10 line 849. An item with only refused store rules now gets a deny rule, so its consent fails closed. A refused rule from either file also keeps its stricter action. The two filed residuals stay open as conditions: C1 (#2441) for the full infrastructure deny set and C2 (#2516) for the creation and expansion wiring.

Ruled at 959d878 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 1 finding, 1 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
@norrietaylor norrietaylor changed the title T25 — Read client-owned store rules and refuse rules in the deny set feat(minimal): read client-owned store rules and refuse rules in the deny set Oct 24, 2026
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

This head merges main into the branch. The merge does not change the four store-rule files. The ruling on 959d878 stands. The configuration-read refusal and the project-section warning conform to Gatehouse §6.10 line 849. C1 (#2441, the full infrastructure deny set) and C2 (#2516, the creation and expansion wiring) stay open as filed residuals.

Ruled at 1b3b848 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
minimal-foundry Bot and others added 3 commits October 24, 2026 22:26
A refused organization deny rule was dropped before the merge, so a user rule for the same
item loosened it. The organization actions as read now set the floor after the merge.
A refused rule no longer drops its item's consent. The item gets a deny rule with no upstream,
and a refused user rule keeps its stricter action.
@norrietaylor
norrietaylor force-pushed the agent/2280-read-client-owned-store-rules-and-refuse-rules-i branch from 1b3b848 to 4e536dc Compare October 24, 2026 22:26
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter verification at 4e536dc. This head is a message-only rewrite of 1b3b848: the two commit messages whose body lines ran to 176 and 145 characters are rewrapped at 100 under the repository's commitlint rule, and the base merge of main fa31776 is recreated on top. The tree is byte-identical to 1b3b848 (git diff 1b3b848d 4e536dc6 is empty), so the review at that head carries: arch PASS, zero open threads, every lane green there. The lanes and the arch review rerun here. Squash title feat(minimal): read client-owned store rules and refuse rules in the deny set and the squashed message now pass commitlint. Residuals #2516 and #2441 are scheduled as T54 and T55 in slice S9.


Generated by Claude Code

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

This head has the same tree as 1b3b848d. Only the history changed, so the earlier ruling stands. The config-read refusal and the project warning conform to Gatehouse §6.10 line 849. The infrastructure deny set is still short of that line (C1, #2441). No creation or expansion path calls the BEP-035 and BEP-036 checks yet (C2, #2516). Both are filed residuals, and the change can merge with them open.

Ruled at 4e536dc against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 1 finding, 1 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 10 of 10 on the runtime's review findings, pushed as 97cf1be249de.

line exit tail
cargo nextest run -p boxes store_rule_in_deny_set_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-25ba... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench
cargo nextest run -p boxes store_rule_naming_sign_in_item_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-2c7d... Finished 'test' profile [unoptimized] target(s) in 0.44s ──────────── Nextest run ID 01a771d8-4675-42d6-9231-4d0ab59fadf0 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes ask_rule_without_tty_denies 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-091c... Finished 'test' profile [unoptimized] target(s) in 0.45s ──────────── Nextest run ID f508891f-16dd-4dec-87d4-4a594c5ae5f2 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes prop_store_upstream_outside_egress_is_exit_3 0 Applying loadouts: default Running task runtime-implement-test-3 in session task-runtime-implement-test-3-5e6c... Finished 'test' profile [unoptimized] target(s) in 0.43s ──────────── Nextest run ID b66b2e16-7c6c-4695-bb93-adc699bc32f8 with nextest profile: default Starting 1 test across 3
cargo nextest run -p boxes project_store_rules_are_ignored_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-41f8... Finished 'test' profile [unoptimized] target(s) in 0.45s ──────────── Nextest run ID bd84ed44-779d-457c-9ae3-de226a6b0bfa with nextest profile: default Starting 1 test across 3

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

0.24.0
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking strum v0.28.0
    Checking sha3 v0.11.0
    Checking p384 v0.14.0
    Checking p521 v0.14.0
    Checking unicode-truncate v2.0.1
    Checking opentelemetry-appender-tracing v0.33.1
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking kasuari v0.4.12
    Checking hash32 v0.3.1
    Checking module-lattice v0.2.3
    Checking lru v0.18.2
    Checking kem v0.3.0
    Checking data-encoding v2.11.1
   Compiling smoltcp v0.14.0
    Checking compression-core v0.4.33
    Checking size v0.5.0
    Checking sponge-cursor v0.1.0
   Compiling litrs v1.0.0
    Checking compression-codecs v0.4.45
    Checking sha3 v0.12.0
   Compiling document-features v0.2.12
    Checking ml-kem v0.3.2
    Checking ratatui-core v0.1.2
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking ssh-key v0.7.0-rc.11
    Checking signal-hook-mio v0.2.5
    Checking op v0.0.1 (/workbench/crates/op)
    Checking generic-array v1.4.4
    Checking derive_more v2.1.1
    Checking russh-cryptovec v0.62.0
   Compiling enum_dispatch v0.3.13
    Checking num-bigint v0.5.1
    Checking russh-util v0.52.0
   Compiling ring v0.17.14
   Compiling delegate v0.13.5
    Checking bitflags v1.3.2
    Checking tinyvec_macros v0.1.1
    Checking constcat v0.6.1
    Checking tagptr v0.2.0
    Checking hex-literal v1.1.0
    Checking managed v0.8.0
    Checking moka v0.12.16
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking russh v0.64.1
    Checking tinyvec v1.12.0
    Checking crossterm v0.29.0
    Checking async-compression v0.4.50
    Checking async-tar v0.6.1
    Checking getrandom v0.2.17
    Checking line-clipping v0.3.8
    Checking object v0.40.0
    Checking is_executable v1.0.6
    Checking clap_complete v4.6.11
    Checking ratatui-widgets v0.3.2
    Checking check v0.0.1 (/workbench/crates/check)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking hickory-proto v0.26.3
    Checking orchestrator v0.0.1 (/workbench/crates/orchestrator)
    Checking yasna v0.6.0
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Review threads the coder judged:

  • 👎 invalid — PRRT_kwDOPdfcxM6v8Rvg: The gap is real, but the fix is outside this task's layers. The deny set is bep::ca::DENY_SET in crates/bep/src/ca.rs, and its doc comment already points to Decide and share the fixed deny set for the box CA name constraints (BEP-013, BEP-034) #2441 for the full §6.10 set. This task reads that set and refuses rules against it. No change this round. (not posted on the thread: not an open thread on the pull request)
  • 👎 invalid — PRRT_kwDOPdfcxM6v8Rvi: This is outside this task's layers. The task delivers the checks and their tests in crates/boxes/src/core/bep.rs. The calls from box creation and expansion belong to files this task does not name, and Call the store-rule checks from box creation and expansion (BEP-034, BEP-035, BEP-036) #2516 tracks them. No change this round. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — crates/boxes/src/core/bep.rs:1104: store_rule_refusal now refuses a basic_auth other than user or password as Malformed { field: "basic_auth" }. The message says the field must be user or password. store_rule_in_deny_set_is_refused_when_malformed pins both.

A secret-store rule in the client configuration that names a GitHub host or the Host header is refused by name when the configuration is read. A rule whose basic_auth is not user or password is now refused too, with a message that names the field and its value.

Notes from the agent: Revise round 10. Only the basic_auth finding needed a code change. store_rule_refusal now refuses a basic_auth other than user or password as Malformed, and the message says the field must be user or password. The malformed test pins this. cargo clippy -p boxes --all-targets is clean. The two arch threads ask for work in files outside this task's layers: crates/bep/src/ca.rs for the full deny set (#2441), and the box creation and expansion paths for the callers (#2516).

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling

This push makes store_rule_refusal refuse a basic_auth that is not user or password. Gatehouse §6.10 line 849 says basic_auth fills one field of the credential, so the new check conforms and fails closed. The change adds no deviation. The two filed conditions from the baseline stay open: C1 (#2441) completes the infrastructure deny set, and C2 (#2516) wires the consent and egress checks into creation and expansion.

Ruled at 97cf1be against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/minimal/src/config.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — approval withheld

Verdict COMMENT — APPROVE withheld: 3 unresolved threads — minimal-foundry[bot] crates/boxes/src/core/bep.rs:1104, minimal-arch[bot] crates/minimal/src/config.rs:219, minimal-arch[bot] crates/boxes/src/core/bep.rs:1276. No findings.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter verification at 97cf1be. Round 10 answers the review bot's LOW on store_rule_refusal: a basic_auth value other than user or password is now refused as Malformed with its own Display case ("has the basic_auth "anything", which is not user or password. Change the rule."), pinned by the new cases in the malformed-rule test, and the two valid values still pass. The diff from 4e536dc is two commits touching only crates/boxes/src/core/bep.rs, inside T25's layers, and the messages pass commitlint. The arch review and the lanes rerun at this head. Squash title feat(minimal): read client-owned store rules and refuse rules in the deny set passes commitlint. Residuals #2516 and #2441 stay scheduled as T54 and T55 in slice S9.


Generated by Claude Code

@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter approval at 97cf1be: every merge gate passes at this head (arch PASS with its two conditions held on the filed residuals #2441 and #2516, zero open threads, every lane aggregator green including ci-macos-success, bot resolutions re-verified). Squash title feat(minimal): read client-owned store rules and refuse rules in the deny set and the squashed message pass commitlint. Queued for squash merge.


Generated by Claude Code

@norrietaylor
norrietaylor added this pull request to the merge queue Oct 24, 2026
Merged via the queue into main with commit 55d0845 Oct 24, 2026
37 checks passed
@norrietaylor
norrietaylor deleted the agent/2280-read-client-owned-store-rules-and-refuse-rules-i branch October 24, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

T25 — Read client-owned store rules and refuse rules in the deny set

1 participant

0