diff --git a/crates/maestro-config/src/lib.rs b/crates/maestro-config/src/lib.rs index 8462982..d8c429d 100644 --- a/crates/maestro-config/src/lib.rs +++ b/crates/maestro-config/src/lib.rs @@ -141,6 +141,9 @@ pub struct DaemonSection { /// back to peer daemons as a T2 dial target. #[serde(default, skip_serializing_if = "Option::is_none")] pub private_addr: Option, + /// `[daemon.policy]` — per-daemon attach policy (NAP-247). + #[serde(default, skip_serializing_if = "DaemonPolicySection::is_empty")] + pub policy: DaemonPolicySection, } impl DaemonSection { @@ -153,6 +156,23 @@ impl DaemonSection { && self.worktree_root.is_none() && self.perimeter_id.is_none() && self.private_addr.is_none() + && self.policy.is_empty() + } +} + +/// `[daemon.policy]` — application-layer access control complementing network +/// ACLs. Default deny: an empty `allow_inbound` rejects every cross-daemon +/// attach. Local attach (no JWT, same daemon) always bypasses. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct DaemonPolicySection { + /// daemon-ids permitted to broker-attach into this daemon's sessions. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub allow_inbound: Vec, +} + +impl DaemonPolicySection { + fn is_empty(&self) -> bool { + self.allow_inbound.is_empty() } } @@ -311,6 +331,9 @@ mod tests { worktree_root: Some(PathBuf::from("/var/lib/maestrod/wt")), perimeter_id: Some("wg-naps62".into()), private_addr: Some("10.0.0.7:7070".into()), + policy: DaemonPolicySection { + allow_inbound: vec!["konishi".into()], + }, }, registry: RegistrySection { bind_addr: Some("0.0.0.0:8080".parse().unwrap()), diff --git a/crates/maestro-daemon/src/config.rs b/crates/maestro-daemon/src/config.rs index 88205d7..0e60d18 100644 --- a/crates/maestro-daemon/src/config.rs +++ b/crates/maestro-daemon/src/config.rs @@ -83,6 +83,9 @@ pub struct DaemonConfig { /// Daemon's reachable address on the declared perimeter. Only meaningful /// when `perimeter_id` is set. pub private_addr: Option, + /// daemon-ids permitted to broker-attach to this daemon's sessions. + /// Default empty (deny all). Local attach bypasses. (NAP-247.) + pub allow_inbound: Vec, } impl DaemonConfig { @@ -194,6 +197,7 @@ pub fn load_config(path: &Path, env: EnvOverrides) -> Result Result