Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2b2cbaf
Correct two gates that describe per-PR enforcement in the present ten…
Aug 19, 2026
199791f
Refuse the argv representation ambiguity instead of silently resolvin…
Aug 19, 2026
b81595f
Merge remote-tracking branch 'origin/main' into session/sharp-ant-396…
Aug 19, 2026
596f356
Merge remote-tracking branch 'origin/main' into session/sharp-ant-396…
Aug 19, 2026
a8de84f
Open the vocabulary axis of realization_vocabulary_containment; falsi…
Aug 19, 2026
81fe0c5
Widen the CLI-vocabulary falsifier root by root; every clean root car…
Aug 19, 2026
85e761d
Close the last roots: the #8535 boundary now reds, stated as infrastr…
Aug 19, 2026
d3543f9
Model the local process-argv seam; fix the trailing-annotation refusa…
Aug 19, 2026
66a7e3a
Move seam rationale to module-item grain; annotations are not admitte…
Aug 19, 2026
4bd7afe
File the finding: admit_callers on a service operation is accepted an…
Aug 19, 2026
decd064
Merge remote-tracking branch 'origin/main' into session/sharp-ant-396…
Aug 19, 2026
2e194db
Retarget the admission control onto the sealed fixture: 54.9s over a …
Aug 19, 2026
88d538f
Cut command_runner's local path onto shell.Exec.RunArgv: argv stops r…
Aug 19, 2026
1526e00
Restrict the literal-words mint to its two callers; state what CI doe…
Aug 19, 2026
71cfb85
Correct a false premise in the trigger I just rewrote: host_effect_ap…
Aug 20, 2026
090dfdc
Replace ShellCaptureResult with ProcessOutcome across every capture site
Aug 20, 2026
00b562e
Site 8: the poison IS persisted, and it defeats the guard — second row
Aug 20, 2026
132cfe6
Merge remote-tracking branch 'origin/main' into session/sharp-ant-396…
Aug 20, 2026
b87367f
Hoist 29 body annotations to module-item grain (§4c), and integrate m…
Aug 20, 2026
0c687e1
Merge remote-tracking branch 'origin/main' into session/sharp-ant-396…
Aug 20, 2026
a750b67
Take main's optional-hostname repair and re-express it on ProcessOutc…
Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 208 additions & 46 deletions dag/gunbc/command_runner.dag

Large diffs are not rendered by default.

30 changes: 17 additions & 13 deletions dag/gunbc/fleet_converge_cli.dag
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import extdeps.filesystem.filesystem_io { Filesystem }
import extdeps.shell
import std.algebra { trim }
import gunbc.command_runner { stat_owner_name_capture }
import extdeps.shell.exec { ProcessOutputPresent, ProcessOutputAbsent, ProcessRefused }
import gunbc.fleet_posix_accounts { fleet_posix_operator_user }

import gunbc.hostname_read {
Expand Down Expand Up @@ -544,19 +545,22 @@ fn converge_cli_expected_receipt_owner_name() -> String {
fn converge_cli_receipt_owner_readback(host: String) -> String? {
let path = fleet_converge_receipt_path(host: host)
let expected = converge_cli_expected_receipt_owner_name()
let r = stat_owner_name_capture(path: path)
if !r.success {
Present { value: concat("gunbc converge: receipt owner read-back refused (stat): ", trim(s: r.stderr)) }
} else {
let owner = trim(s: r.stdout)
if owner == expected {
none
} else {
Present {
value: concat(
concat("gunbc converge: receipt owner read-back mismatch — expected ", expected),
concat(" observed ", owner),
),
match stat_owner_name_capture(path: path) {
ProcessRefused { exit_code: _, stderr: e } =>
Present { value: concat("gunbc converge: receipt owner read-back refused (stat): ", trim(s: e)) }
ProcessOutputAbsent =>
Present { value: "gunbc converge: receipt owner read-back refused (stat): admitted exit but no owner name on stdout" }
ProcessOutputPresent { text: t } => {
let owner = trim(s: t)
if owner == expected {
none
} else {
Present {
value: concat(
concat("gunbc converge: receipt owner read-back mismatch — expected ", expected),
concat(" observed ", owner),
),
}
}
}
}
Expand Down
35 changes: 25 additions & 10 deletions dag/gunbc/fleet_converge_plan_cli.dag
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import std.algebra { trim }
import std.content_hash { serialize_content_hash }
import extdeps.filesystem.filesystem_io { Filesystem }
import extdeps.exec.command { ArgvCommand, LocalExec }
import gunbc.command_runner { run_shell_command_capture, run_shell_commands }
import gunbc.command_runner { run_shell_command_capture, run_shell_commands, process_outcome_admitted }
import gunbc.host_axis_caps { CapMember, caps_managed_dropin_paths }
import gunbc.fleet_converge_plan {
TimerRetirementMember,
Expand Down Expand Up @@ -40,18 +40,33 @@ data fleet_converge_plan_spark_typed_actions_wire_path: String = "/tmp/fleet-con

data fleet_converge_plan_cli_note: String = "Wet CLI for on-demand fleet converge plan/apply (sleek-heron-218). Plan observes the host, runs membership_reconcile once, names the subject (host + member-set fingerprint), mints a std.temporal_effect LeaseEpoch generation in the artifact, and writes the human-readable plan plus apply.sh. plan_content.hex is the Fnv1a64Structural bundle digest of plan.txt + apply.sh + spark_serving_typed_actions.wire (empty wire on non-Spark hosts); on success plan_wet prints plan.txt then that digest for workflow_dispatch plan_artifact_hash. Apply re-observes subject identity and observed-baseline fingerprint in .dag, refuses unless on-disk plan.txt + apply.sh + spark wire match plan_content.hex, then runs fleet_converge_locked_apply_script under flock. Generation store reads refuse corrupt or negative values; a missing store file is generation 0. Subject host is a typed observation (observe_host_short_wet returns NonEmptyStr?, Absent when the hostname probe did not succeed or returned empty output): both plan and apply refuse outright on Absent rather than folding a failed probe into an empty String, and the SubjectHostMismatch check itself routes through fleet_converge_apply_subject_host_matches on two NonEmptyStr values (gunbc.fleet_converge_plan) — the same authority fleet_converge_apply_subject_admits uses — never a bare String != that two coincident non-observations (both hosts probed empty) could satisfy by accident."

// MAIN CLOSED THIS ONE AND THIS BRANCH DOES NOT RE-OPEN IT. The optional return IS the next-rung
// repair this lane named -- an unreadable hostname is now Absent rather than a String that looks
// like a hostname, both plan and apply refuse on Absent, and the subject comparison routes through
// a typed authority over two NonEmptyStr values instead of a bare String equality that two
// coincident non-observations could satisfy. The defeated-guard defect is fixed, not surfaced.
//
// WHAT CHANGED HERE IS ONLY THE PROBE'S INPUT SHAPE. main derived Absent from `!run.success ||
// trimmed == ""`, reading a record this branch deletes; the same judgment now reads the arms of
// ProcessOutcome. The three arms map to exactly the two states main distinguished, so the behaviour
// is preserved rather than re-decided: Refused and Absent are both non-observations, and a Present
// arm whose text trims empty is still Absent, because ProcessOutputPresent means the process wrote
// bytes -- not that those bytes name a host.
func observe_host_short_wet() -> NonEmptyStr?
uses net: Network
{
let run = run_shell_command_capture(
match run_shell_command_capture(
command: ArgvCommand { argv: ["hostname", "-s"] },
transport: LocalExec,
)
let trimmed = trim(s: run.stdout)
if !run.success || trimmed == "" {
none
} else {
Present { value: trimmed as NonEmptyStr }
) {
ProcessOutputPresent { text: t } =>
if trim(s: t) == "" {
none
} else {
Present { value: trim(s: t) as NonEmptyStr }
}
ProcessOutputAbsent => none
ProcessRefused { exit_code: _, stderr: _ } => none
}
}

Expand All @@ -67,10 +82,10 @@ func observe_timer_members_wet() -> List<TimerRetirementMember>
{
let legacy = timer_retirement_observed_legacy_srv1()
filter(legacy, m =>
run_shell_command_capture(
process_outcome_admitted(outcome: run_shell_command_capture(
command: ArgvCommand { argv: ["test", "-f", concat("/etc/systemd/system/", m.unit_name as String)] },
transport: LocalExec,
).success
))
)
}

Expand Down
115 changes: 81 additions & 34 deletions dag/gunbc/fleet_host_key_enrollment.dag
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import std.decl_ref { DeclarationRef, WholeDeclaration }
import extdeps.filesystem.filesystem_io { Filesystem }
import extdeps.exec.command { ArgvCommand, LocalExec }
import extdeps.ssh { ssh_public_key_line }
import gunbc.command_runner { run_shell_commands, run_shell_command_capture, ShellCaptureResult }
import gunbc.command_runner { run_shell_commands, run_shell_command_capture, process_outcome_admitted, process_outcome_receipt_text }
import extdeps.shell.exec { ProcessOutcome, ProcessOutputPresent, ProcessOutputAbsent, ProcessRefused }
import product.placement_supply { HostIdentity }
import gunbc.fleet_reach_endpoint { fleet_probe_endpoint_for, fleet_reach_probe_targets }
import gunbc.fleet_ssh_access { fleet_automation_ssh_key, fleet_automation_privkey_version_segment, fleet_automation_ssh_privkey_secret }
Expand Down Expand Up @@ -169,32 +170,67 @@ data fleet_host_key_scan_receipt_path: String = "target/fleet-host-key-scan-rece
// bold-eagle measurements and OpenSSH defaults lead with), then fingerprint the scanned
// line. Both captures ride the receipt VERBATIM with a per-host outcome label; a
// refusing scan is a typed absent line, never an empty fabrication.
// Post-apply verification. Hoisted out of the apply arms so both admitted arms share one route,
// and matched rather than read: the old code did concat("outcome=", trim(verify.stdout)), so a
// verify that REFUSED emitted the literal receipt line "outcome=" -- a fabricated plausible output
// standing where the answer was unknown, written into a receipt someone would later read as fact.
func verify_enrollment_outcome() -> String
uses net: Network
{
match run_shell_command_capture(
command: ArgvCommand { argv: ["sh", "-c", "H=$(getent passwd \"$(whoami)\" | cut -d: -f6); grep -qxF \"$(cat target/fleet-authorized-key-line | head -1)\" \"$H/.ssh/authorized_keys\" && echo enrolled || echo ABSENT-after-apply"] },
transport: LocalExec,
) {
ProcessOutputPresent { text: t } => concat("outcome=", trim(s: t))
ProcessOutputAbsent => "outcome=UNKNOWN cause=verify admitted but printed nothing"
ProcessRefused { exit_code: _, stderr: e } => join(["outcome=UNKNOWN cause=verify refused: ", trim(s: e)], "")
}
}

// ProcessOutputPresent already means admitted-and-non-empty, so the old
// `scan.success && trim(scan.stdout) != ""` correlation is the variant itself rather than a
// condition the caller must remember to write. ProcessOutputAbsent is now a NAMED outcome --
// ssh-keyscan exiting 0 with no key is a different fact from ssh-keyscan failing, and the old
// shape reported both as "refused" with an empty cause.

// The old code fabricated a ShellCaptureResult here to stand in for a FILESYSTEM failure --
// a process result for something that was never a process, with an invented success: false.
// The coproduct makes that unwritable, which is the point: a write failure is not a process
// outcome and now has to be said in its own words.

fn scan_host_key_lines(host: String) -> String {
let endpoint = fleet_probe_endpoint_for(host: host)
let scan = run_shell_command_capture(
match run_shell_command_capture(
command: ArgvCommand { argv: ["ssh-keyscan", "-T", "5", "-t", "ed25519", endpoint] },
transport: LocalExec,
)
if scan.success && trim(s: scan.stdout) != "" {
let key_file = join(["target/fleet-host-key-scan-", host, ".pub"], "")
let w = Filesystem.Write(path: key_file, content: scan.stdout)
let fp = if w.success {
run_shell_command_capture(
command: ArgvCommand { argv: ["ssh-keygen", "-l", "-f", key_file] },
transport: LocalExec,
)
} else {
ShellCaptureResult { success: false, stdout: "", stderr: w.error }
) {
ProcessOutputPresent { text: key_text } => {
let key_file = join(["target/fleet-host-key-scan-", host, ".pub"], "")
let w = Filesystem.Write(path: key_file, content: key_text)
let fingerprint_text = if w.success {
process_outcome_receipt_text(
outcome: run_shell_command_capture(
command: ArgvCommand { argv: ["ssh-keygen", "-l", "-f", key_file] },
transport: LocalExec,
)
)
} else {
join(["(not computed: staging write refused: ", w.error, ")"], "")
}
join([
"scan host=", host, " endpoint=", endpoint, " outcome=observed\n",
"key ", trim(s: key_text), "\n",
"fingerprint ", fingerprint_text, "\n",
], "")
}
join([
"scan host=", host, " endpoint=", endpoint, " outcome=observed\n",
"key ", trim(s: scan.stdout), "\n",
"fingerprint ", trim(s: fp.stdout), "\n",
], "")
} else {
join([
"scan host=", host, " endpoint=", endpoint, " outcome=refused cause=", trim(s: scan.stderr), "\n",
], "")
ProcessOutputAbsent =>
join([
"scan host=", host, " endpoint=", endpoint, " outcome=no-key-offered cause=scan admitted but returned no key\n",
], "")
ProcessRefused { exit_code: _, stderr: e } =>
join([
"scan host=", host, " endpoint=", endpoint, " outcome=refused cause=", trim(s: e), "\n",
], "")
}
}

Expand Down Expand Up @@ -278,7 +314,7 @@ func fleet_host_key_enroll_apply() -> String
join([
"enroll host=", k.host as String, " endpoint=", k.endpoint,
" provenance=", host_key_provenance_label(p: k.provenance),
if f.success { " readback=found-in-pinned-fragment" } else { " readback=ABSENT" }, "\n",
if process_outcome_admitted(outcome: f) { " readback=found-in-pinned-fragment" } else { " readback=ABSENT" }, "\n",
], "")
}), "")
}
Expand Down Expand Up @@ -321,6 +357,13 @@ fn fleet_automation_authorized_keys_line() -> String {
ssh_public_key_line(k: fleet_automation_ssh_key)
}

// THE DEFECT THIS MIGRATION EXISTS FOR. The old test was `trim(check.stdout) == "present"`
// with no consultation of success, so a probe that FAILED produced "" -- not "present" -- and
// fell through to the else branch, which APPLIES. A refusal to read the file was therefore
// indistinguishable from the key being absent, and the remedy for the two states is opposite:
// absent means write it, unreadable means stop and say so. Matching the arms makes the third
// state impossible to fall through: a refusal now refuses instead of mutating the file.

func fleet_authorized_key_self_enroll_wet() -> ProcessExit
uses net: Network
{
Expand All @@ -334,29 +377,33 @@ func fleet_authorized_key_self_enroll_wet() -> ProcessExit
command: ArgvCommand { argv: ["sh", "-c", "H=$(getent passwd \"$(whoami)\" | cut -d: -f6); grep -qxF \"$(cat target/fleet-authorized-key-line | head -1)\" \"$H/.ssh/authorized_keys\" 2>/dev/null && echo present || echo absent"] },
transport: LocalExec,
)
if trim(s: check.stdout) == "present" {
match check {
ProcessRefused { exit_code: _, stderr: ce } =>
join(["outcome=refused cause=presence-probe refused, not applying: ", trim(s: ce)], "")
ProcessOutputAbsent =>
"outcome=refused cause=presence-probe admitted but printed nothing, not applying"
ProcessOutputPresent { text: ct } =>
if trim(s: ct) == "present" {
"outcome=already-present"
} else {
let apply = run_shell_command_capture(
command: ArgvCommand { argv: ["sh", "-c", "H=$(getent passwd \"$(whoami)\" | cut -d: -f6); mkdir -p \"$H/.ssh\" && chmod 700 \"$H/.ssh\" && touch \"$H/.ssh/authorized_keys\" && chmod 600 \"$H/.ssh/authorized_keys\" && cat target/fleet-authorized-key-line >> \"$H/.ssh/authorized_keys\""] },
transport: LocalExec,
)
if apply.success {
let verify = run_shell_command_capture(
command: ArgvCommand { argv: ["sh", "-c", "H=$(getent passwd \"$(whoami)\" | cut -d: -f6); grep -qxF \"$(cat target/fleet-authorized-key-line | head -1)\" \"$H/.ssh/authorized_keys\" && echo enrolled || echo ABSENT-after-apply"] },
transport: LocalExec,
)
concat("outcome=", trim(s: verify.stdout))
} else {
join(["outcome=refused cause=", trim(s: apply.stderr)], "")
match apply {
ProcessRefused { exit_code: _, stderr: ae } =>
join(["outcome=refused cause=", trim(s: ae)], "")
ProcessOutputPresent { text: _ } => verify_enrollment_outcome()
ProcessOutputAbsent => verify_enrollment_outcome()
}
}
}
} else {
join(["outcome=refused cause=staging: ", w.error], "")
}
let body = join([
"authorized-key-self-enroll host=", trim(s: hostname.stdout),
" user=", trim(s: user.stdout), " ", outcome, "\n",
"authorized-key-self-enroll host=", process_outcome_receipt_text(outcome: hostname),
" user=", process_outcome_receipt_text(outcome: user), " ", outcome, "\n",
], "")
let wr = Filesystem.Write(path: fleet_authorized_key_enroll_receipt_path, content: body)
if wr.success {
Expand Down
42 changes: 26 additions & 16 deletions dag/gunbc/fleet_probe_identity_observe.dag
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import std.process { ProcessExit, ExitSuccess, exit_failure }
import std.resources { Network }
import extdeps.filesystem.filesystem_io { Filesystem }
import extdeps.exec.command { ArgvCommand, LocalExec }
import gunbc.command_runner { run_shell_command_capture }
import gunbc.command_runner { run_shell_command_capture, process_outcome_receipt_text }
import extdeps.shell.exec { ProcessOutcome, ProcessOutputPresent, ProcessOutputAbsent, ProcessRefused }
import gunbc.fleet_ssh_access { fleet_automation_ssh_key }

// Observe-first for the probe-identity decision (parent msg_156e62bd): READ-ONLY
Expand All @@ -20,28 +21,37 @@ import gunbc.fleet_ssh_access { fleet_automation_ssh_key }
data fleet_probe_identity_receipt_path: String = "target/fleet-probe-identity-observe-receipt.txt"

fn observe_capture_line(label: String, argv: List<String>) -> String {
let r = run_shell_command_capture(command: ArgvCommand { argv: argv }, transport: LocalExec)
if r.success {
join([label, " outcome=observed value=", trim(s: r.stdout), "\n"], "")
} else {
join([label, " outcome=refused cause=", trim(s: r.stderr), "\n"], "")
match run_shell_command_capture(command: ArgvCommand { argv: argv }, transport: LocalExec) {
ProcessOutputPresent { text: t } =>
join([label, " outcome=observed value=", trim(s: t), "\n"], "")
ProcessOutputAbsent =>
join([label, " outcome=observed-empty value=\n"], "")
ProcessRefused { exit_code: _, stderr: e } =>
join([label, " outcome=refused cause=", trim(s: e), "\n"], "")
}
}

fn observe_authorized_keys_line(home: String) -> String {
let path = concat(home, "/.ssh/authorized_keys")
let read = run_shell_command_capture(command: ArgvCommand { argv: ["cat", path] }, transport: LocalExec)
if read.success {
if string_contains(s: read.stdout, pattern: fleet_automation_ssh_key.material) {
match run_shell_command_capture(command: ArgvCommand { argv: ["cat", path] }, transport: LocalExec) {
ProcessOutputPresent { text: read_text } =>
if string_contains(s: read_text, pattern: fleet_automation_ssh_key.material) {
join(["authorized-keys home=", home, " outcome=fleet-key-present\n"], "")
} else {
join(["authorized-keys home=", home, " outcome=fleet-key-absent (file readable, key material not found)\n"], "")
}
} else {
join(["authorized-keys home=", home, " outcome=unreadable cause=", trim(s: read.stderr), "\n"], "")
ProcessOutputAbsent =>
join(["authorized-keys home=", home, " outcome=fleet-key-absent (file readable and empty)\n"], "")
ProcessRefused { exit_code: _, stderr: e } =>
join(["authorized-keys home=", home, " outcome=unreadable cause=", trim(s: e), "\n"], "")
}
}

// ph and jh are USED AS PATHS below, not merely printed, so they match the arms rather than
// routing through the receipt-text projection: "(refused: ...)" is fine to print and wrong to
// open. An unreadable home yields "" here and the guarded call below skips the probe entirely
// rather than reading /.ssh/authorized_keys off a fabricated root.

func fleet_probe_identity_observe_wet() -> ProcessExit
uses net: Network
{
Expand All @@ -54,13 +64,13 @@ func fleet_probe_identity_observe_wet() -> ProcessExit
command: ArgvCommand { argv: ["sh", "-c", "echo \"$HOME\"" ] },
transport: LocalExec,
)
let ph = trim(s: passwd_home.stdout)
let jh = trim(s: job_home.stdout)
let ph = match passwd_home { ProcessOutputPresent { text: t } => trim(s: t) ProcessOutputAbsent => "" ProcessRefused { exit_code: _, stderr: _ } => "" }
let jh = match job_home { ProcessOutputPresent { text: t } => trim(s: t) ProcessOutputAbsent => "" ProcessRefused { exit_code: _, stderr: _ } => "" }
let body = join([
join(["observer user=", trim(s: user.stdout), " passwd-home=", ph, " job-home=", jh, "\n"], ""),
join(["observer user=", process_outcome_receipt_text(outcome: user), " passwd-home=", process_outcome_receipt_text(outcome: passwd_home), " job-home=", process_outcome_receipt_text(outcome: job_home), "\n"], ""),
"local-host-note only the host this runner occupies is locally observable pre-auth; srv2-srv4 authorized_keys standing is PENDING-FIRST-AUTH (recorded, not assumed)\n",
observe_authorized_keys_line(home: ph),
if jh != ph { observe_authorized_keys_line(home: jh) } else { "" },
if ph != "" { observe_authorized_keys_line(home: ph) } else { "authorized-keys home=(passwd home unreadable) outcome=not-probed\n" },
if jh != ph && jh != "" { observe_authorized_keys_line(home: jh) } else { "" },
observe_capture_line(label: "gcloud-binary", argv: ["sh", "-c", "command -v gcloud || echo absent"]),
observe_capture_line(label: "gcloud-auth-list", argv: ["sh", "-c", "command -v gcloud >/dev/null && gcloud auth list --format=value(account) 2>&1 || echo gcloud-absent"]),
observe_capture_line(label: "adc-env", argv: ["sh", "-c", "echo \"$\{GOOGLE_APPLICATION_CREDENTIALS:-absent}\""]),
Expand Down
Loading