Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ fn sudo_nopasswd_execute_probe_shell_condition(probe: SudoNopasswdExecuteProbeSh
// binary not yet installed would read as a grant miss (the reason this probe kind exists).
data sudo_nopasswd_grant_list_tag: String = "NOPASSWD:"

// THE LAST STAGE READS THE WHOLE LISTING. `grep -q` exits at its first match while sed is still
// writing, and under pipefail the writer's SIGPIPE (141) fails the pipeline -- so a grant that IS
// listed early in a long listing read as absent, every time once the listing outgrew the pipe
// buffer (srv1, 2026-10-10: ~13 KB after the gunbc-ghrunner drop-in, 20/20 runs exit 141). `grep -Fx`
// with stdout discarded consumes all of it and still answers by its exit status alone.
fn sudo_nopasswd_grant_list_shell_condition(probe: SudoNopasswdGrantListProbeShape) -> Node {
let tag = sudo_nopasswd_grant_list_tag
bash_build_pipe(
Expand All @@ -103,7 +108,10 @@ fn sudo_nopasswd_grant_list_shell_condition(probe: SudoNopasswdGrantListProbeSha
left: bash_build_command_from_lits(lits: ["sed", "-n", concat(concat("s/^.*", tag), "//p")]),
right: bash_build_pipe(
left: bash_build_command_from_lits(lits: ["sed", "s/^[[:space:]]*//;s/[[:space:]]*$//"]),
right: bash_build_command_from_lits(lits: ["grep", "-Fqx", "--", probe as String])
right: bash_build_with_redir(
inner: bash_build_command_from_lits(lits: ["grep", "-Fx", "--", probe as String]),
redir: ^bash_production_fold_redir_stdout_null
)
)
)
)
Expand Down
14 changes: 13 additions & 1 deletion dag/gunbc/live_deploy/spec.dag
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import gunbc.roadmap_dashboard_instance {
HostDashboardInstance,
dashboard_instance_provider_state_root,
dashboard_instance_tailnet_door_socket,
dashboard_instance_tailnet_door_directory,
}
import extdeps.http.server { HttpServerListenConfig }
import gunbc.auth.approval_broker_endpoint { approval_broker_listen_port, approval_broker_listen_host, approval_broker_confirm_front_door }
Expand Down Expand Up @@ -1334,7 +1335,18 @@ fn deployment_spec_for(
),
names: names,
instance_id: instance.instance_id,
directories: dashboard_instance_directory_demands(instance: instance),
directories: concat(dashboard_instance_directory_demands(instance: instance), deployment_tailnet_door_directories(instance: instance, names: names)),
}
}

// THE DOOR'S DIRECTORY IS A DEPLOYMENT DEMAND, NOT AN INSTANCE ONE: only a deployment whose serve
// route targets a unix socket runs a door (deployment_tailnet_door_socket), and only the spec knows
// the route. It joins the instance's own list here, so the one provider ensures and reads it back
// before the door unit binds; a deployment routed to a port demands nothing.
fn deployment_tailnet_door_directories(instance: HostDashboardInstance, names: DeploymentNames) -> List<OwnedDirectoryTarget> {
match deployment_tailnet_door_socket(names: names) {
Present { value: _ } => [dashboard_instance_tailnet_door_directory(instance: instance)]
Absent => []
}
}

Expand Down
5 changes: 5 additions & 0 deletions dag/gunbc/roadmap/dashboard_instance_directories.dag
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import gunbc.fabric_storage_placement { fabric_storage_directory_demands }
// writes, at which point this list stops being authored. Until then, adding a directory writer means
// declaring its demand in its own module and adding one row here.
//
// A DEPLOYMENT'S OWN DEMANDS ARE NOT INSTANCE CONSUMERS: the tailnet door's directory exists only
// where a deployment's serve route targets a unix socket, which the instance does not know, so
// gunbc.live_deploy.spec deployment_spec_for appends it (deployment_tailnet_door_directories) to this
// list for the live_deploy route. The dashboard apply runs no door and reads this list alone.
//
// It lives above the consumers rather than in gunbc.roadmap_dashboard_instance because every consumer
// imports the instance type from there; composing them there would close a cycle.
fn dashboard_instance_directory_demands(instance: HostDashboardInstance) -> List<OwnedDirectoryTarget> {
Expand Down
17 changes: 13 additions & 4 deletions dag/gunbc/roadmap/roadmap_dashboard_instance.dag
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,20 @@ fn dashboard_instance_child(root: FilePath, child: String) -> FilePath {
join([root as String, "/", child], "") as FilePath
}
// THE INSTANCE'S TAILNET DOOR: the unix socket its door unit serves on and tailscale serve proxies
// to. It sits in the instance root, which the service principal owns; who may open it is not what
// the door relies on -- the handler is handed the kernel-attested peer of every connection
// (`gunbc serve --unix-socket`, peer_user) and only tailscaled's is the proxy.
// to. It sits in a directory of its own under the instance root, which the deployment ensures owned
// by the service principal: the instance root itself need not be the principal's to write (srv1's
// /opt/gunbc is root-owned 0755 and the deploy re-asserts it), so a socket bound directly in it
// could not be created and readiness, which requires the door, could never hold (srv1 precondition
// sweep, 2026-10-10) -- the defect roadmap_event_carrier_directory answered for the event worktree.
// Who may open the socket is not what the door relies on -- the handler is handed the
// kernel-attested peer of every connection (`gunbc serve --unix-socket`, peer_user) and only
// tailscaled's is the proxy.
fn dashboard_instance_tailnet_door_directory(instance: HostDashboardInstance) -> OwnedDirectoryTarget {
dashboard_instance_shared_directory(instance: instance, member: "tailnet-door" as NonEmptyStr, child: "tailnet-door")
}

fn dashboard_instance_tailnet_door_socket(instance: HostDashboardInstance) -> NonEmptyStr {
dashboard_instance_child(root: instance.instance_root, child: "tailnet-door.sock") as String as NonEmptyStr
join([owned_directory_path(t: dashboard_instance_tailnet_door_directory(instance: instance)) as String, "/door.sock"], "") as NonEmptyStr
}

fn dashboard_instance_provider_state_root(instance: HostDashboardInstance) -> FilePath {
Expand Down