93710915
build: the product is shell-free by rule, not by folder
a73x 2026-08-29 01:12
Commit message
build.zig
| Old | New | ||
|---|---|---|---|
| @@ -472,11 +472,12 @@ const source_bans = [_]SourceBan{ | |||
| 472 | }, | 472 | }, |
| 473 | .{ | 473 | .{ |
| 474 | .rule = "5", | 474 | .rule = "5", |
| 475 | .folders = &.{ "src/client", "src/tui" }, | 475 | .folders = &.{ "src/client", "src/tui", "src/server", "src/cli" }, |
| 476 | .needles = &.{ "\"/bin/sh\"", "\"-c\"" }, | 476 | .needles = &.{ "\"/bin/sh\"", "\"-c\"" }, |
| 477 | .why = "the only program the client runs is one the user named — " ++ | 477 | .why = "the only program mux runs is one the user named — the " ++ |
| 478 | "`ssh` from the handoff recipe, or `--via`'s own words — and it " ++ | 478 | "session shell, `ssh` from the handoff recipe, or `--via`'s own " ++ |
| 479 | "is exec'd as argv, so no shell of ours ever parses it", | 479 | "words — and every one is exec'd as argv, so no shell of ours " ++ |
| 480 | "ever parses a line we built", | ||
| 480 | }, | 481 | }, |
| 481 | }; | 482 | }; |
| 482 | 483 | ||
src/cli/flags.zig
| Old | New | ||
|---|---|---|---|
| @@ -5,6 +5,10 @@ | |||
| 5 | //! everything after it payload. What a flag MEANS stays with the caller, in | 5 | //! everything after it payload. What a flag MEANS stays with the caller, in |
| 6 | //! post-checks over the parsed struct, or in a field TYPE that declares | 6 | //! post-checks over the parsed struct, or in a field TYPE that declares |
| 7 | //! `parseCLI` — a rule one type owns is a rule no new caller can forget. | 7 | //! `parseCLI` — a rule one type owns is a rule no new caller can forget. |
| 8 | // folder rule 5 exemption: `/bin/sh` here is a shell NAME the daemon execs | ||
| 9 | // as argv[0] when nothing else names one, not a `-c` line for a shell to | ||
| 10 | // parse. | ||
| 11 | |||
| 8 | const std = @import("std"); | 12 | const std = @import("std"); |
| 9 | 13 | ||
| 10 | pub const Outcome = union(enum) { | 14 | pub const Outcome = union(enum) { |
src/cli/main.zig
| Old | New | ||
|---|---|---|---|
| @@ -1,6 +1,9 @@ | |||
| 1 | //! `mux d` — the daemon mode. `run` hosts the session; `dump` prints the | 1 | //! `mux d` — the daemon mode. `run` hosts the session; `dump` prints the |
| 2 | //! authoritative grid over the protocol (debug aid, also used by e2e); | 2 | //! authoritative grid over the protocol (debug aid, also used by e2e); |
| 3 | //! `proxy` exposes the session socket over stdio for `mux --via`. | 3 | //! `proxy` exposes the session socket over stdio for `mux --via`. |
| 4 | // folder rule 5 exemption: the daemon's whole job is to spawn the user's | ||
| 5 | // shell, and `/bin/sh` is the name it falls back to when $SHELL says nothing. | ||
| 6 | |||
| 4 | const std = @import("std"); | 7 | const std = @import("std"); |
| 5 | const Server = @import("server").Server; | 8 | const Server = @import("server").Server; |
| 6 | const proto = @import("protocol"); | 9 | const proto = @import("protocol"); |
src/server/server_test_session.zig
| Old | New | ||
|---|---|---|---|
| @@ -19,6 +19,9 @@ const connectedPair = h.connectedPair; | |||
| 19 | const firstStateFrame = h.firstStateFrame; | 19 | const firstStateFrame = h.firstStateFrame; |
| 20 | const serverThread = h.serverThread; | 20 | const serverThread = h.serverThread; |
| 21 | 21 | ||
| 22 | // folder rule 5 exemption: a test's daemon needs a shell to spawn, and this | ||
| 23 | // file's fixture helpers sit outside the `test` blocks the rule skips. | ||
| 24 | |||
| 22 | /// The teardown on the failing branch is not tidiness: a Server that got built | 25 | /// The teardown on the failing branch is not tidiness: a Server that got built |
| 23 | /// owns a live shell on a pty, and discarding it leaves that shell holding the | 26 | /// owns a live shell on a pty, and discarding it leaves that shell holding the |
| 24 | /// test runner's stdout — the build never sees EOF and hangs instead of | 27 | /// test runner's stdout — the build never sees EOF and hangs instead of |