commit 343a9f76c1298f9a8d1e2b37cc1f3c1bff54d3b2
parent 830a5a4f05ba6a1233f5144a80bd5de1516c4322
Author: triesap <tyson@radroots.org>
Date: Sat, 22 Aug 2026 05:13:38 +0000
cli: freeze one-pass execution authority
Diffstat:
9 files changed, 640 insertions(+), 5 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
@@ -107,6 +107,13 @@
cursors to route/filter/snapshot identity and must retain exact operation-ID
replay/conflict evidence before returning success. Do not infer relay
delivery from a successful local mutation and do not add TCP admin routes.
+- Step 152 freezes the one-parse CLI execution split. Every admitted command
+ must select exactly daemon, offline, or permissioned Unix-admin authority;
+ only the explicitly contracted read-only status, backup, and public-identity
+ operations may fall back after proving the daemon writer lock is free.
+ Rekey, replace, and every other live mutation have no direct-state fallback.
+ Do not reparse process arguments or let a live CLI plan obtain SQLite,
+ provider, relay, task, signal, or runtime authority.
- Treat checked-in source, tests, and prototype behavior as implementation
evidence, not permission to preserve behavior that the active requirement
removes.
diff --git a/README b/README
@@ -52,6 +52,14 @@ The process binary uses only this parser. Hardened command execution remains
fail-closed until its ordered runtime-dispatch steps are complete; no prototype
command is used as a fallback.
+The parsed invocation is projected once into a sealed execution plan. `run`
+selects daemon authority; config, exclusive state/identity provisioning, and
+doctor select offline authority; state/identity/service inspection and live
+mutations select the permissioned Unix-admin authority. Only explicitly
+read-only status, backup, and public-identity operations may fall back when a
+later executor proves the daemon writer lock is free. Rekey and replace never
+fall back to direct state access, and no live plan carries SQLite authority.
+
`parse_myc_config_v1` caps original bytes before decoding, checks the schema
header before closed contract admission, rejects duplicate, null, unknown, and
semantically inconsistent input, and returns an immutable document plus a
diff --git a/contracts/api_baselines/myc.txt b/contracts/api_baselines/myc.txt
@@ -103,6 +103,27 @@ pub enum myc::MycBootstrapProfileV1
pub myc::MycBootstrapProfileV1::Interactive
pub myc::MycBootstrapProfileV1::RepoLocal
pub myc::MycBootstrapProfileV1::ServiceHost
+pub enum myc::MycCliAdminOperationV1
+pub myc::MycCliAdminOperationV1::IdentityPublic
+pub myc::MycCliAdminOperationV1::IdentityRekey
+pub myc::MycCliAdminOperationV1::IdentityReplace
+pub myc::MycCliAdminOperationV1::IdentityStatus
+pub myc::MycCliAdminOperationV1::StateBackup
+pub myc::MycCliAdminOperationV1::StateStatus
+pub myc::MycCliAdminOperationV1::Status
+impl myc::MycCliAdminOperationV1
+pub const fn myc::MycCliAdminOperationV1::route(self) -> myc::MycAdminRoute
+pub enum myc::MycCliOfflineOperationV1
+pub myc::MycCliOfflineOperationV1::Config
+pub myc::MycCliOfflineOperationV1::Doctor
+pub myc::MycCliOfflineOperationV1::IdentityExclusive
+pub myc::MycCliOfflineOperationV1::IdentityReadOnly
+pub myc::MycCliOfflineOperationV1::StateExclusive
+pub myc::MycCliOfflineOperationV1::StateReadOnly
+pub enum myc::MycCliPrimaryAuthorityV1
+pub myc::MycCliPrimaryAuthorityV1::Daemon
+pub myc::MycCliPrimaryAuthorityV1::LiveUnixAdmin
+pub myc::MycCliPrimaryAuthorityV1::Offline
pub enum myc::MycCliV1ErrorKind
pub myc::MycCliV1ErrorKind::InvalidArguments
pub myc::MycCliV1ErrorKind::InvalidConfigPath
@@ -712,6 +733,14 @@ pub fn myc::MycBoundedNip46Request::plaintext_bytes(&self) -> usize
pub const fn myc::MycBoundedNip46Request::request_id_bytes(&self) -> usize
impl core::fmt::Debug for myc::MycBoundedNip46Request
pub fn myc::MycBoundedNip46Request::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+pub struct myc::MycCliExecutionPlanV1
+impl myc::MycCliExecutionPlanV1
+pub const fn myc::MycCliExecutionPlanV1::admin_operation(&self) -> core::option::Option<myc::MycCliAdminOperationV1>
+pub const fn myc::MycCliExecutionPlanV1::allows_daemon_unavailable_offline_fallback(&self) -> bool
+pub const fn myc::MycCliExecutionPlanV1::offline_operation(&self) -> core::option::Option<myc::MycCliOfflineOperationV1>
+pub const fn myc::MycCliExecutionPlanV1::primary_authority(&self) -> myc::MycCliPrimaryAuthorityV1
+impl core::fmt::Debug for myc::MycCliExecutionPlanV1
+pub fn myc::MycCliExecutionPlanV1::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct myc::MycCliInvocationV1
impl myc::MycCliInvocationV1
pub const fn myc::MycCliInvocationV1::command(&self) -> myc::MycCommandV1
@@ -1700,6 +1729,7 @@ pub async fn myc::open_myc_state_inspection(&myc::MycRuntimeContext, &myc::MycSt
pub async fn myc::open_myc_state_read_write(&myc::MycRuntimeContext, &myc::MycStateMetadata, radroots_service_sqlite::migration::MigrationAppliedAtUnixSeconds, &radroots_service_sqlite::migration::MigrationBuildIdentity) -> core::result::Result<myc::MycStateHost, myc::MycStateHostError>
pub fn myc::parse_myc_cli_v1_from<I, T>(I) -> core::result::Result<myc::MycCliInvocationV1, myc::MycCliV1Error> where I: core::iter::traits::collect::IntoIterator<Item = T>, T: core::convert::Into<std::ffi::os_str::OsString> + core::clone::Clone
pub fn myc::parse_myc_config_v1(&[u8], myc::MycConfigProfile) -> core::result::Result<myc::MycConfigDocumentV1, myc::MycConfigV1Error>
+pub const fn myc::plan_myc_cli_v1(&myc::MycCliInvocationV1) -> myc::MycCliExecutionPlanV1
pub fn myc::prepare_myc_nip46_decrypt_work(myc::MycVerifiedNip46Event, &myc::MycProviderBinding, myc::MycProviderDeadlineUnixMs) -> core::result::Result<myc::MycNip46DecryptWork, myc::MycNip46WorkError>
pub fn myc::prepare_myc_nip46_request(myc::MycDecryptedNip46Request, myc::MycSignerOperationNonce, myc::MycRequestReceivedAtUnixMs) -> core::result::Result<myc::MycPreparedNip46Request, myc::MycNip46WorkError>
pub fn myc::prepare_myc_nip46_work(myc::MycPreparedNip46Request, myc::MycSignerRequestRecord, core::option::Option<myc::MycConnectionRecord>, &myc::MycProviderContract, myc::MycConnectionTimeUnixMs, core::option::Option<myc::MycProviderDeadlineUnixMs>) -> core::result::Result<myc::MycNip46Work, myc::MycNip46WorkError>
diff --git a/contracts/services_hardening/operator_contract.v1.json b/contracts/services_hardening/operator_contract.v1.json
@@ -242,6 +242,33 @@
}
}
},
+ "cli_dispatch": {
+ "parse_count": 1,
+ "primary_authorities": ["daemon", "offline", "live_unix_admin"],
+ "live_direct_sqlite_access": false,
+ "live_mutation_offline_fallback": false,
+ "read_only_offline_fallback_requires_free_daemon_writer_lock": true,
+ "commands": [
+ { "command": "run", "primary_authority": "daemon" },
+ { "command": "config init", "primary_authority": "offline", "offline_operation": "config" },
+ { "command": "config validate", "primary_authority": "offline", "offline_operation": "config" },
+ { "command": "config show", "primary_authority": "offline", "offline_operation": "config" },
+ { "command": "config schema", "primary_authority": "offline", "offline_operation": "config" },
+ { "command": "state init", "primary_authority": "offline", "offline_operation": "state_exclusive" },
+ { "command": "state status", "primary_authority": "live_unix_admin", "admin_route": "/v1/state/status", "offline_operation": "state_read_only", "daemon_unavailable_offline_fallback": true },
+ { "command": "state backup", "primary_authority": "live_unix_admin", "admin_route": "/v1/state/backup", "offline_operation": "state_read_only", "daemon_unavailable_offline_fallback": true },
+ { "command": "state restore", "primary_authority": "offline", "offline_operation": "state_exclusive" },
+ { "command": "state verify", "primary_authority": "offline", "offline_operation": "state_exclusive" },
+ { "command": "state migrate", "primary_authority": "offline", "offline_operation": "state_exclusive" },
+ { "command": "identity init", "primary_authority": "offline", "offline_operation": "identity_exclusive" },
+ { "command": "identity status", "primary_authority": "live_unix_admin", "admin_route": "/v1/identity/status", "offline_operation": "identity_read_only", "daemon_unavailable_offline_fallback": true },
+ { "command": "identity rekey", "primary_authority": "live_unix_admin", "admin_route": "/v1/identity/rekey" },
+ { "command": "identity replace", "primary_authority": "live_unix_admin", "admin_route": "/v1/identity/replace" },
+ { "command": "identity export-public", "primary_authority": "live_unix_admin", "admin_route": "/v1/identity/public", "offline_operation": "identity_read_only", "daemon_unavailable_offline_fallback": true },
+ { "command": "status", "primary_authority": "live_unix_admin", "admin_route": "/v1/status", "offline_operation": "state_read_only", "daemon_unavailable_offline_fallback": true },
+ { "command": "doctor", "primary_authority": "offline", "offline_operation": "doctor" }
+ ]
+ },
"doctor": {
"shared_schema": "radroots.service.doctor.v1",
"contract_version": 1,
diff --git a/src/cli_v1.rs b/src/cli_v1.rs
@@ -58,6 +58,120 @@ pub enum MycIdentityCommandV1 {
ExportPublic,
}
+/// The only three process authorities selected by the hardened CLI.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum MycCliPrimaryAuthorityV1 {
+ Daemon,
+ Offline,
+ LiveUnixAdmin,
+}
+
+/// The closed offline operation classes selected before any state access.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum MycCliOfflineOperationV1 {
+ Config,
+ StateExclusive,
+ StateReadOnly,
+ IdentityExclusive,
+ IdentityReadOnly,
+ Doctor,
+}
+
+/// The closed Unix-admin operations reachable from the command inventory.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum MycCliAdminOperationV1 {
+ Status,
+ StateStatus,
+ StateBackup,
+ IdentityStatus,
+ IdentityRekey,
+ IdentityReplace,
+ IdentityPublic,
+}
+
+#[cfg(any(target_os = "linux", target_os = "macos"))]
+impl MycCliAdminOperationV1 {
+ /// Returns the exact native Unix-admin route selected by this operation.
+ #[must_use]
+ pub const fn route(self) -> crate::MycAdminRoute {
+ match self {
+ Self::Status => crate::MycAdminRoute::Status,
+ Self::StateStatus => crate::MycAdminRoute::StateStatus,
+ Self::StateBackup => crate::MycAdminRoute::StateBackup,
+ Self::IdentityStatus => crate::MycAdminRoute::IdentityStatus,
+ Self::IdentityRekey => crate::MycAdminRoute::IdentityRekey,
+ Self::IdentityReplace => crate::MycAdminRoute::IdentityReplace,
+ Self::IdentityPublic => crate::MycAdminRoute::IdentityPublic,
+ }
+ }
+}
+
+/// A sealed, side-effect-free execution plan for one admitted CLI invocation.
+///
+/// Construction is owned by [`plan_myc_cli_v1`]. A live mutation never carries
+/// an offline fallback, while explicitly read-only status, backup, and public
+/// identity operations may fall back only after later execution proves the
+/// daemon writer lock is free.
+///
+/// ```compile_fail
+/// use myc::{MycCliExecutionPlanV1, MycCliPrimaryAuthorityV1};
+///
+/// let _ = MycCliExecutionPlanV1 {
+/// primary_authority: MycCliPrimaryAuthorityV1::Offline,
+/// offline_operation: None,
+/// admin_operation: None,
+/// daemon_unavailable_offline_fallback: true,
+/// };
+/// ```
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct MycCliExecutionPlanV1 {
+ primary_authority: MycCliPrimaryAuthorityV1,
+ offline_operation: Option<MycCliOfflineOperationV1>,
+ admin_operation: Option<MycCliAdminOperationV1>,
+ daemon_unavailable_offline_fallback: bool,
+}
+
+impl MycCliExecutionPlanV1 {
+ /// Returns the authority that must be attempted first.
+ #[must_use]
+ pub const fn primary_authority(&self) -> MycCliPrimaryAuthorityV1 {
+ self.primary_authority
+ }
+
+ /// Returns the bounded offline operation, when the plan admits one.
+ #[must_use]
+ pub const fn offline_operation(&self) -> Option<MycCliOfflineOperationV1> {
+ self.offline_operation
+ }
+
+ /// Returns the bounded Unix-admin operation, when the plan admits one.
+ #[must_use]
+ pub const fn admin_operation(&self) -> Option<MycCliAdminOperationV1> {
+ self.admin_operation
+ }
+
+ /// Returns whether a missing daemon may fall back to read-only offline work.
+ #[must_use]
+ pub const fn allows_daemon_unavailable_offline_fallback(&self) -> bool {
+ self.daemon_unavailable_offline_fallback
+ }
+}
+
+impl fmt::Debug for MycCliExecutionPlanV1 {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter
+ .debug_struct("MycCliExecutionPlanV1")
+ .field("primary_authority", &self.primary_authority)
+ .field("offline_operation", &self.offline_operation)
+ .field("admin_operation", &self.admin_operation)
+ .field(
+ "daemon_unavailable_offline_fallback",
+ &self.daemon_unavailable_offline_fallback,
+ )
+ .finish()
+ }
+}
+
/// Stable source-free classification for command-line admission failures.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MycCliV1ErrorKind {
@@ -213,6 +327,94 @@ where
})
}
+/// Selects the sole permitted execution authority for an admitted command.
+///
+/// This function performs no filesystem, database, socket, environment, task,
+/// or process work. Later executors consume the plan without reparsing process
+/// arguments. In particular, no live command receives direct SQLite authority.
+#[must_use]
+pub const fn plan_myc_cli_v1(invocation: &MycCliInvocationV1) -> MycCliExecutionPlanV1 {
+ match invocation.command {
+ MycCommandV1::Run => daemon_plan(),
+ MycCommandV1::Config(_) => offline_plan(MycCliOfflineOperationV1::Config),
+ MycCommandV1::State(MycStateCommandV1::Init)
+ | MycCommandV1::State(MycStateCommandV1::Restore)
+ | MycCommandV1::State(MycStateCommandV1::Verify)
+ | MycCommandV1::State(MycStateCommandV1::Migrate) => {
+ offline_plan(MycCliOfflineOperationV1::StateExclusive)
+ }
+ MycCommandV1::State(MycStateCommandV1::Status) => read_only_admin_plan(
+ MycCliAdminOperationV1::StateStatus,
+ MycCliOfflineOperationV1::StateReadOnly,
+ ),
+ MycCommandV1::State(MycStateCommandV1::Backup) => read_only_admin_plan(
+ MycCliAdminOperationV1::StateBackup,
+ MycCliOfflineOperationV1::StateReadOnly,
+ ),
+ MycCommandV1::Identity(MycIdentityCommandV1::Init) => {
+ offline_plan(MycCliOfflineOperationV1::IdentityExclusive)
+ }
+ MycCommandV1::Identity(MycIdentityCommandV1::Status) => read_only_admin_plan(
+ MycCliAdminOperationV1::IdentityStatus,
+ MycCliOfflineOperationV1::IdentityReadOnly,
+ ),
+ MycCommandV1::Identity(MycIdentityCommandV1::ExportPublic) => read_only_admin_plan(
+ MycCliAdminOperationV1::IdentityPublic,
+ MycCliOfflineOperationV1::IdentityReadOnly,
+ ),
+ MycCommandV1::Identity(MycIdentityCommandV1::Rekey) => {
+ admin_plan(MycCliAdminOperationV1::IdentityRekey)
+ }
+ MycCommandV1::Identity(MycIdentityCommandV1::Replace) => {
+ admin_plan(MycCliAdminOperationV1::IdentityReplace)
+ }
+ MycCommandV1::Status => read_only_admin_plan(
+ MycCliAdminOperationV1::Status,
+ MycCliOfflineOperationV1::StateReadOnly,
+ ),
+ MycCommandV1::Doctor => offline_plan(MycCliOfflineOperationV1::Doctor),
+ }
+}
+
+const fn daemon_plan() -> MycCliExecutionPlanV1 {
+ MycCliExecutionPlanV1 {
+ primary_authority: MycCliPrimaryAuthorityV1::Daemon,
+ offline_operation: None,
+ admin_operation: None,
+ daemon_unavailable_offline_fallback: false,
+ }
+}
+
+const fn offline_plan(operation: MycCliOfflineOperationV1) -> MycCliExecutionPlanV1 {
+ MycCliExecutionPlanV1 {
+ primary_authority: MycCliPrimaryAuthorityV1::Offline,
+ offline_operation: Some(operation),
+ admin_operation: None,
+ daemon_unavailable_offline_fallback: false,
+ }
+}
+
+const fn admin_plan(operation: MycCliAdminOperationV1) -> MycCliExecutionPlanV1 {
+ MycCliExecutionPlanV1 {
+ primary_authority: MycCliPrimaryAuthorityV1::LiveUnixAdmin,
+ offline_operation: None,
+ admin_operation: Some(operation),
+ daemon_unavailable_offline_fallback: false,
+ }
+}
+
+const fn read_only_admin_plan(
+ admin_operation: MycCliAdminOperationV1,
+ offline_operation: MycCliOfflineOperationV1,
+) -> MycCliExecutionPlanV1 {
+ MycCliExecutionPlanV1 {
+ primary_authority: MycCliPrimaryAuthorityV1::LiveUnixAdmin,
+ offline_operation: Some(offline_operation),
+ admin_operation: Some(admin_operation),
+ daemon_unavailable_offline_fallback: true,
+ }
+}
+
fn validate_bootstrap_paths(
profile: MycBootstrapProfileV1,
repo_local_root: Option<&Path>,
diff --git a/src/lib.rs b/src/lib.rs
@@ -43,8 +43,10 @@ pub use admin_v1::{
build_myc_admin_router,
};
pub use cli_v1::{
- MycBootstrapProfileV1, MycCliInvocationV1, MycCliV1Error, MycCliV1ErrorKind, MycCommandV1,
- MycConfigCommandV1, MycIdentityCommandV1, MycStateCommandV1, parse_myc_cli_v1_from,
+ MycBootstrapProfileV1, MycCliAdminOperationV1, MycCliExecutionPlanV1, MycCliInvocationV1,
+ MycCliOfflineOperationV1, MycCliPrimaryAuthorityV1, MycCliV1Error, MycCliV1ErrorKind,
+ MycCommandV1, MycConfigCommandV1, MycIdentityCommandV1, MycStateCommandV1,
+ parse_myc_cli_v1_from, plan_myc_cli_v1,
};
pub use config_v1::{
MYC_CONFIG_DOCUMENT_MAX_UTF8_BYTES, MYC_CONFIG_SCHEMA, MYC_CONFIG_SCHEMA_VERSION,
diff --git a/src/main.rs b/src/main.rs
@@ -4,7 +4,8 @@ use std::process::ExitCode;
fn main() -> ExitCode {
match myc::parse_myc_cli_v1_from(std::env::args_os()) {
- Ok(_) => {
+ Ok(invocation) => {
+ let _plan = myc::plan_myc_cli_v1(&invocation);
eprintln!("myc: command execution is unavailable");
ExitCode::FAILURE
}
diff --git a/tests/package_boundary.rs b/tests/package_boundary.rs
@@ -119,6 +119,11 @@ fn implementation_modules_are_private_and_rustdoc_uses_the_reviewed_readme() {
#[test]
fn reviewed_api_is_root_only_and_exposes_no_implementation_authority() {
for required in [
+ "pub struct myc::MycCliExecutionPlanV1",
+ "pub enum myc::MycCliPrimaryAuthorityV1",
+ "pub enum myc::MycCliOfflineOperationV1",
+ "pub enum myc::MycCliAdminOperationV1",
+ "pub const fn myc::plan_myc_cli_v1",
"pub struct myc::MycAdminRequestDocument",
"pub struct myc::MycAdminResponseDocument",
"pub enum myc::MycAdminMethod",
diff --git a/tests/services_hardening_cli.rs b/tests/services_hardening_cli.rs
@@ -1,14 +1,19 @@
#![forbid(unsafe_code)]
+use std::collections::BTreeSet;
use std::error::Error;
use std::path::Path;
use myc::{
- INSTANCE_ID_MAX_BYTES, MycBootstrapProfileV1, MycCliV1ErrorKind, MycCommandV1,
- MycConfigCommandV1, MycIdentityCommandV1, MycStateCommandV1, parse_myc_cli_v1_from,
+ INSTANCE_ID_MAX_BYTES, MycBootstrapProfileV1, MycCliAdminOperationV1, MycCliOfflineOperationV1,
+ MycCliPrimaryAuthorityV1, MycCliV1ErrorKind, MycCommandV1, MycConfigCommandV1,
+ MycIdentityCommandV1, MycStateCommandV1, parse_myc_cli_v1_from, plan_myc_cli_v1,
};
const CLI_SOURCE: &str = include_str!("../src/cli_v1.rs");
+const MAIN_SOURCE: &str = include_str!("../src/main.rs");
+const OPERATOR_CONTRACT: &str =
+ include_str!("../contracts/services_hardening/operator_contract.v1.json");
fn base(command: &[&str]) -> Vec<String> {
let mut arguments = vec![
@@ -130,6 +135,345 @@ fn root_api_exposes_validated_cross_bound_bootstrap_values() {
}
#[test]
+fn every_command_has_one_exact_nonforgeable_execution_plan() {
+ let vectors = [
+ ("run", vec!["run"], "daemon", None, None, false),
+ (
+ "config init",
+ vec!["config", "init"],
+ "offline",
+ Some("config"),
+ None,
+ false,
+ ),
+ (
+ "config validate",
+ vec!["config", "validate"],
+ "offline",
+ Some("config"),
+ None,
+ false,
+ ),
+ (
+ "config show",
+ vec!["config", "show"],
+ "offline",
+ Some("config"),
+ None,
+ false,
+ ),
+ (
+ "config schema",
+ vec!["config", "schema"],
+ "offline",
+ Some("config"),
+ None,
+ false,
+ ),
+ (
+ "state init",
+ vec!["state", "init"],
+ "offline",
+ Some("state_exclusive"),
+ None,
+ false,
+ ),
+ (
+ "state status",
+ vec!["state", "status"],
+ "live_unix_admin",
+ Some("state_read_only"),
+ Some("/v1/state/status"),
+ true,
+ ),
+ (
+ "state backup",
+ vec!["state", "backup"],
+ "live_unix_admin",
+ Some("state_read_only"),
+ Some("/v1/state/backup"),
+ true,
+ ),
+ (
+ "state restore",
+ vec!["state", "restore"],
+ "offline",
+ Some("state_exclusive"),
+ None,
+ false,
+ ),
+ (
+ "state verify",
+ vec!["state", "verify"],
+ "offline",
+ Some("state_exclusive"),
+ None,
+ false,
+ ),
+ (
+ "state migrate",
+ vec!["state", "migrate"],
+ "offline",
+ Some("state_exclusive"),
+ None,
+ false,
+ ),
+ (
+ "identity init",
+ vec!["identity", "init"],
+ "offline",
+ Some("identity_exclusive"),
+ None,
+ false,
+ ),
+ (
+ "identity status",
+ vec!["identity", "status"],
+ "live_unix_admin",
+ Some("identity_read_only"),
+ Some("/v1/identity/status"),
+ true,
+ ),
+ (
+ "identity rekey",
+ vec!["identity", "rekey"],
+ "live_unix_admin",
+ None,
+ Some("/v1/identity/rekey"),
+ false,
+ ),
+ (
+ "identity replace",
+ vec!["identity", "replace"],
+ "live_unix_admin",
+ None,
+ Some("/v1/identity/replace"),
+ false,
+ ),
+ (
+ "identity export-public",
+ vec!["identity", "export-public"],
+ "live_unix_admin",
+ Some("identity_read_only"),
+ Some("/v1/identity/public"),
+ true,
+ ),
+ (
+ "status",
+ vec!["status"],
+ "live_unix_admin",
+ Some("state_read_only"),
+ Some("/v1/status"),
+ true,
+ ),
+ (
+ "doctor",
+ vec!["doctor"],
+ "offline",
+ Some("doctor"),
+ None,
+ false,
+ ),
+ ];
+ let contract: serde_json::Value =
+ serde_json::from_str(OPERATOR_CONTRACT).expect("operator contract");
+ let dispatch = contract
+ .get("cli_dispatch")
+ .and_then(serde_json::Value::as_object)
+ .expect("CLI dispatch contract");
+ assert_eq!(
+ dispatch.keys().map(String::as_str).collect::<BTreeSet<_>>(),
+ BTreeSet::from([
+ "commands",
+ "live_direct_sqlite_access",
+ "live_mutation_offline_fallback",
+ "parse_count",
+ "primary_authorities",
+ "read_only_offline_fallback_requires_free_daemon_writer_lock",
+ ])
+ );
+ assert_eq!(
+ dispatch
+ .get("parse_count")
+ .and_then(serde_json::Value::as_u64),
+ Some(1)
+ );
+ assert_eq!(
+ dispatch
+ .get("live_direct_sqlite_access")
+ .and_then(serde_json::Value::as_bool),
+ Some(false)
+ );
+ assert_eq!(
+ dispatch.get("primary_authorities"),
+ Some(&serde_json::json!(["daemon", "offline", "live_unix_admin"]))
+ );
+ assert_eq!(
+ dispatch
+ .get("read_only_offline_fallback_requires_free_daemon_writer_lock")
+ .and_then(serde_json::Value::as_bool),
+ Some(true)
+ );
+ assert_eq!(
+ dispatch
+ .get("live_mutation_offline_fallback")
+ .and_then(serde_json::Value::as_bool),
+ Some(false)
+ );
+ let commands = dispatch
+ .get("commands")
+ .and_then(serde_json::Value::as_array)
+ .expect("command inventory");
+ assert_eq!(commands.len(), vectors.len());
+
+ for (index, (command, arguments, authority, offline, route, fallback)) in
+ vectors.into_iter().enumerate()
+ {
+ let invocation = parse_myc_cli_v1_from(base(&arguments)).expect("command");
+ let plan = plan_myc_cli_v1(&invocation);
+ assert_eq!(authority_name(plan.primary_authority()), authority);
+ assert_eq!(plan.offline_operation().map(offline_name), offline);
+ assert_eq!(plan.admin_operation().map(admin_path), route);
+ assert_eq!(plan.allows_daemon_unavailable_offline_fallback(), fallback);
+
+ let row = commands[index].as_object().expect("command row");
+ let mut expected_keys = BTreeSet::from(["command", "primary_authority"]);
+ if offline.is_some() {
+ expected_keys.insert("offline_operation");
+ }
+ if route.is_some() {
+ expected_keys.insert("admin_route");
+ }
+ if fallback {
+ expected_keys.insert("daemon_unavailable_offline_fallback");
+ }
+ assert_eq!(
+ row.keys().map(String::as_str).collect::<BTreeSet<_>>(),
+ expected_keys
+ );
+ assert_eq!(
+ row.get("command").and_then(serde_json::Value::as_str),
+ Some(command)
+ );
+ assert_eq!(
+ row.get("primary_authority")
+ .and_then(serde_json::Value::as_str),
+ Some(authority)
+ );
+ assert_eq!(
+ row.get("offline_operation")
+ .and_then(serde_json::Value::as_str),
+ offline
+ );
+ assert_eq!(
+ row.get("admin_route").and_then(serde_json::Value::as_str),
+ route
+ );
+ assert_eq!(
+ row.get("daemon_unavailable_offline_fallback")
+ .and_then(serde_json::Value::as_bool)
+ .unwrap_or(false),
+ fallback
+ );
+ }
+}
+
+fn authority_name(authority: MycCliPrimaryAuthorityV1) -> &'static str {
+ match authority {
+ MycCliPrimaryAuthorityV1::Daemon => "daemon",
+ MycCliPrimaryAuthorityV1::Offline => "offline",
+ MycCliPrimaryAuthorityV1::LiveUnixAdmin => "live_unix_admin",
+ }
+}
+
+fn offline_name(operation: MycCliOfflineOperationV1) -> &'static str {
+ match operation {
+ MycCliOfflineOperationV1::Config => "config",
+ MycCliOfflineOperationV1::StateExclusive => "state_exclusive",
+ MycCliOfflineOperationV1::StateReadOnly => "state_read_only",
+ MycCliOfflineOperationV1::IdentityExclusive => "identity_exclusive",
+ MycCliOfflineOperationV1::IdentityReadOnly => "identity_read_only",
+ MycCliOfflineOperationV1::Doctor => "doctor",
+ }
+}
+
+fn admin_path(operation: MycCliAdminOperationV1) -> &'static str {
+ match operation {
+ MycCliAdminOperationV1::Status => "/v1/status",
+ MycCliAdminOperationV1::StateStatus => "/v1/state/status",
+ MycCliAdminOperationV1::StateBackup => "/v1/state/backup",
+ MycCliAdminOperationV1::IdentityStatus => "/v1/identity/status",
+ MycCliAdminOperationV1::IdentityRekey => "/v1/identity/rekey",
+ MycCliAdminOperationV1::IdentityReplace => "/v1/identity/replace",
+ MycCliAdminOperationV1::IdentityPublic => "/v1/identity/public",
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "macos"))]
+#[test]
+fn cli_admin_operations_match_the_governed_route_inventory() {
+ use myc::MycAdminRoute;
+
+ let vectors = [
+ (MycCliAdminOperationV1::Status, MycAdminRoute::Status),
+ (
+ MycCliAdminOperationV1::StateStatus,
+ MycAdminRoute::StateStatus,
+ ),
+ (
+ MycCliAdminOperationV1::StateBackup,
+ MycAdminRoute::StateBackup,
+ ),
+ (
+ MycCliAdminOperationV1::IdentityStatus,
+ MycAdminRoute::IdentityStatus,
+ ),
+ (
+ MycCliAdminOperationV1::IdentityRekey,
+ MycAdminRoute::IdentityRekey,
+ ),
+ (
+ MycCliAdminOperationV1::IdentityReplace,
+ MycAdminRoute::IdentityReplace,
+ ),
+ (
+ MycCliAdminOperationV1::IdentityPublic,
+ MycAdminRoute::IdentityPublic,
+ ),
+ ];
+ for (operation, route) in vectors {
+ assert_eq!(operation.route(), route);
+ assert_eq!(admin_path(operation), route.path());
+ }
+}
+
+#[test]
+fn execution_plan_debug_retains_no_bootstrap_or_path_values() {
+ let invocation = parse_myc_cli_v1_from([
+ "myc",
+ "--profile",
+ "repo-local",
+ "--instance",
+ "secret-instance",
+ "--repo-local-root",
+ "/secret/repository",
+ "--config",
+ "/secret/config.toml",
+ "identity",
+ "rekey",
+ ])
+ .expect("valid invocation");
+ let rendered = format!("{invocation:?} {:?}", plan_myc_cli_v1(&invocation));
+ for forbidden in [
+ "secret-instance",
+ "/secret/repository",
+ "/secret/config.toml",
+ ] {
+ assert!(!rendered.contains(forbidden));
+ }
+}
+
+#[test]
fn root_api_rejects_prototype_and_arbitrary_leaf_arguments_safely() {
for arguments in [
base(&["--env-file", "/secret/config.env", "run"]),
@@ -157,10 +501,19 @@ fn parser_is_single_pass_pure_and_privately_implemented() {
"serde_json::",
"toml::",
"pub mod cli_v1",
+ "sqlx::",
+ "open_myc_state_",
+ "MycStateHost",
] {
assert!(!CLI_SOURCE.contains(forbidden), "found `{forbidden}`");
}
+ assert_eq!(MAIN_SOURCE.matches("parse_myc_cli_v1_from").count(), 1);
+ assert_eq!(MAIN_SOURCE.matches("plan_myc_cli_v1").count(), 1);
+ for forbidden in ["sqlx::", "open_myc_state_", "MycStateHost"] {
+ assert!(!MAIN_SOURCE.contains(forbidden), "found `{forbidden}`");
+ }
+
let root = include_str!("../src/lib.rs");
assert!(root.contains("mod cli_v1;"));
assert!(!root.contains("pub mod cli_v1;"));