Skip to content

I3996 — A node's provisioning secret is read on mc's standard input, never from a command line

mesh build-cache provision creates a node's MinIO identity with `mc admin user add <alias> <access key>` and passes the secret on the command's standard input. That is mc's own documented form (minio/mc cmd/admin-user-add.go, fetchUserKeys), so the secret is in no process's argv.

BLOCKED wave 2 · p1 · implementation profile · parallel safe

Part of builds-reuse-the-mesh-cache — Builds reuse the mesh cache: compiled Rust, the cargo build directory, mix deps and npm packages, keyed by platform, toolchain and inputs.

Blocked. This issue cannot start until I2674, milestone:builds-reuse-the-mesh-cache are done. The status is derived from that, not declared.

Objective

mesh build-cache provision creates a node's MinIO identity with `mc admin user add <alias> <access key>` and passes the secret on the command's standard input. That is mc's own documented form (minio/mc cmd/admin-user-add.go, fetchUserKeys), so the secret is in no process's argv.

Why

Found in review of I2674 (#2402) on 2026-10-23, and on master since train 6 (b62848cb6f5): apps/majordomus-cli/src/mesh/cache_provision.rs appended each node's generated secret to the argv of `mc admin user add`. Every user of the provider host can read an argv in ps and /proc/<pid>/cmdline for as long as the call runs. The intent this milestone serves says no credential appears in a process's environment, a log or an answer, and an argument is all three at once. Only `mesh build-cache provision --apply` on a provider host runs the call, and none has been run (lundra, the intended host, has not been provisioned), so no secret has been exposed and none needs rotating.

Current state

Measured at master b62848cb6f5 on 2026-10-25: run_steps builds `mc --quiet admin user add <alias> mesh-cache-<node>`, pushes the secret onto that argv (cache_provision.rs:908-909), and the runner gives the child no standard input.

Desired state

The identity step's argv ends at the access key. The runner writes the secret, followed by a newline, to the child's standard input and closes it. Every other command gets a null standard input. The step's printed line names where the secret goes, never the secret itself.

Scope

  • apps/majordomus-cli/src/mesh/cache_provision.rs
  • .ai/repo/project/issues/I3996.yaml

Out of scope

  • A gate and rule that refuse a secret on any command line the repository runs (I4224, train 8)
  • Rotating identities: none was ever created through the argv form

Dependencies

Acceptance criteria

  • With a recording runner, no argv of any command the apply runs contains any node's secret, and each node's secret, followed by a newline, is the standard input of exactly its own admin user add
  • The real runner gives a stand-in mc the input on its standard input and nothing on its command line; a command given no input reads an empty, closed standard input

Validation

  • cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib mesh::cache_provision
  • bin/majordomus plan validate

Evidence required

  • suite

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Timeline

started
—
verified
—
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I3996.yaml. Read it back with majordomus plan show I3996.

Searches the titles and descriptions of every page this site publishes.