Task files, the files they copy in (byte-identical to the reference on m3a-ref), each area's check record, and a README with the per-task table of what each check exposed. The handoff note is done with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.0 KiB
5.0 KiB
M3a task 04: brokerd's configuration
Branch: m3a (run git switch m3a; git status --short must be empty, otherwise stop)
Commit subject: Add brokerd's configuration
Goal
brokerd.toml into a typed Config. This is a format we define: unknown keys are errors, in
every table. It works like crates/loopd/src/config.rs; read that file first and follow its style.
# brokerd.toml — every key is optional
[paths]
home = "/var/lib/boxmaker" # default: $BOXMAKER_HOME, then /var/lib/boxmaker
grants = "/etc/boxmaker/grants"
[sockets]
broker = "/var/lib/boxmaker/run/loop-broker/broker.sock" # default: under home
admin = "/var/lib/boxmaker/run/owner-broker/admin.sock" # default: under home
[approvals]
ttl_ms = 900000 # 15 min
Files
- Copy:
crates/brokerd/tests/config.rs, and the six files incrates/brokerd/tests/fixtures/config/ - Create:
crates/brokerd/src/config.rs - Modify:
crates/brokerd/src/lib.rs(addpub mod config;),crates/brokerd/Cargo.toml,docs/dependencies.md,docs/implementer-log.md
brokerd gains three dependencies, all already in [workspace.dependencies]. Add to
crates/brokerd/Cargo.toml under [dependencies]:
serde.workspace = true
serde_json.workspace = true
toml.workspace = true
In docs/dependencies.md, add brokerd to the "Used by" cell of the serde row and of the
serde_json row (for example `proto`, `brokerd`). The toml row already names brokerd.
Change nothing else in that file.
Interfaces
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Paths { pub home: PathBuf, pub grants: PathBuf }
/// An empty path means "the default under `home`".
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
#[serde(deny_unknown_fields, default)]
pub struct Sockets { pub broker: PathBuf, pub admin: PathBuf }
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Approvals { pub ttl_ms: u64 }
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
#[serde(deny_unknown_fields)]
pub struct Config {
#[serde(default)] pub paths: Paths,
#[serde(default)] pub sockets: Sockets,
#[serde(default)] pub approvals: Approvals,
}
#[derive(Debug)]
pub enum ConfigError { Read(PathBuf, std::io::Error), Parse(PathBuf, toml::de::Error) }
impl Config {
pub fn parse(text: &str) -> Result<Config, toml::de::Error>;
pub fn load(path: &Path) -> Result<Config, ConfigError>;
pub fn broker_socket(&self) -> PathBuf;
pub fn admin_socket(&self) -> PathBuf;
pub fn audit_dir(&self) -> PathBuf;
pub fn state_dir(&self) -> PathBuf;
}
Rules
impl Default for Paths:homeis$BOXMAKER_HOMEif the variable is set, otherwise/var/lib/boxmaker;grantsis/etc/boxmaker/grants. Copy howloopd'sPathsreads the variable (std::env::var_os).impl Default for Approvals:ttl_msis900_000.deny_unknown_fieldsgoes on all four structs:Paths,Sockets,ApprovalsandConfig. The test checks an unknown key in each table and at the top level.broker_socket(): ifsockets.brokeris empty,homejoined withrun/loop-broker/broker.sock; otherwisesockets.broker.admin_socket(): the same withrun/owner-broker/admin.sock. Test for empty withas_os_str().is_empty(), asloopd'schannel_socketdoes.audit_dir()ishomejoined withaudit.state_dir()ishomejoined withbroker/sessions. Neither can be set on its own.load: a file that cannot be read isConfigError::Read(path, err), including a missing file; a file that does not parse isConfigError::Parse(path, err).ConfigErrorimplementsDisplay(the path,:, the inner error) andstd::error::Error, by hand.- Do not set or change environment variables anywhere, tests included.
Steps
- 1. Copy.
git switch m3a, thenmkdir -p crates/brokerd/tests/fixtures && cp docs/plans/M3a/files/crates/brokerd/tests/config.rs crates/brokerd/tests/ && cp -r docs/plans/M3a/files/crates/brokerd/tests/fixtures/config crates/brokerd/tests/fixtures/ - 2. See the test fail.
cargo test -p brokerd --test config. Expected: it does not compile. - 3. Add the dependencies, write
config.rs, addpub mod config;. Runcargo buildonce soCargo.lockis updated, thencargo fmt --all. - 4. See the tests pass.
cargo test -p brokerd --test config. Expected:7 passed. - 5. Run the gate.
make gate. Expected last line:gate: ok. - 6. Log and commit.
git add crates/brokerd Cargo.lock docs/dependencies.md docs/implementer-log.md && git commit
Done when
cargo test -p brokerd --test configreports 7 passed;make gateprintsgate: ok.
Stop and report if
[workspace.dependencies]in the rootCargo.tomllacksserde,serde_jsonortoml.- A test seems to need an environment variable to be set.