Files
kyleandClaude Opus 5.5 64190c3701 M5a plan: task 16, the gate passes on macOS; the review's tasks become 17 to 20
The work moved to titan (macOS), where the gate failed for reasons older
than M5a: sockets under macOS's long TMPDIR pass its 104-byte limit,
gatewayd reads /proc/self for its uid, and /tmp is /private/tmp. Task 16
sets TMPDIR=/tmp for every process Cargo runs (.cargo/config.toml [env]),
has gatewayd take its uid from the owner of a pipe it makes (no dependency,
no unsafe), and hands over a toolkit shell.rs that compares resolved paths.
On a scratch tree the gate passes on titan and on talos with 936 tests, and
a wrong uid fails 7 gatewayd tests. Tasks 16 to 19 are renumbered 17 to 20.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 16:41:44 -07:00

4.4 KiB

M5a task 16: the gate passes on macOS as well as on Linux

Branch: m5a (run git switch m5a; git status --short must be empty, otherwise stop) Commit subject: gate: pass on macOS: tests use /tmp, gatewayd finds its uid without /proc

Goal

Work moved to titan, a Mac, on 2026-09-24. There make gate fails although the code is right, because three places assume Linux. The harness itself still runs on straylight (Linux); this task only makes the gate pass on both. No behaviour change on Linux, and no new test.

  1. Unix socket paths are too long. Tests put sockets under std::env::temp_dir(). On macOS that is /var/folders/…/T/, about 50 bytes, and a socket's whole path may be at most 104 bytes there, so some tests' daemons cannot bind (for example brokerd's serve_runner.rs and gatewayd's serve_restart.rs). A new .cargo/config.toml sets TMPDIR=/tmp for every process Cargo runs, tests included.
  2. gatewayd reads /proc/self for the user id it runs as, when it checks a secret file's owner. macOS has no /proc. std has no call for the user id, and unsafe (for libc) is not allowed, so a new function user_id takes the owner of a pipe the process has just made, which is the user the process runs as on Linux and on macOS (checked on both: 1000 on talos, 501 on titan, the same as id -u).
  3. toolkit's shell.rs test expects pwd to print /tmp; on macOS /tmp is a link to /private/tmp, and pwd prints the resolved path. A new version of that given test compares with the resolved path.

Files

  • Create: .cargo/config.toml (at the repository root, next to Cargo.toml)
  • Copy: a new version of the given crates/toolkit/tests/shell.rs, from docs/plans/M5a/files/crates/toolkit/tests/shell.rs
  • Modify: crates/gatewayd/src/secrets.rs, docs/implementer-log.md

The changes, exactly

1. Create .cargo/config.toml with exactly this content:

# Tests put Unix sockets under `std::env::temp_dir()`. macOS's is long (/var/folders/…/T/), and a
# socket's path there can pass the 104 bytes macOS allows, so every process Cargo runs, tests
# included, uses /tmp.
[env]
TMPDIR = { value = "/tmp", force = true }

2. crates/gatewayd/src/secrets.rs, in read_checked. Nothing else in the file changes.

a. In the comment, the line

    //    on `named`): the uid of "/proc/self"; "<path> is not owned by the user gatewayd runs as";

becomes

    //    on `named`): the uid of `user_id()`; "<path> is not owned by the user gatewayd runs as";

b. The three lines

    let owner = std::fs::metadata("/proc/self")
        .map_err(|e| format!("cannot read /proc/self: {}", e))?
        .uid();

become the one line

    let owner = user_id()?;

c. Insert this function immediately above the line /// The text without one trailing newline; not empty; UTF-8. (the doc comment of value), with one blank line between them:

/// The user id this process runs as: the owner of a pipe it has just made. `std` has no call for
/// it, and `/proc/self` is Linux only.
fn user_id() -> Result<u32, String> {
    let (reader, _writer) = std::io::pipe().map_err(|e| format!("cannot make a pipe: {e}"))?;
    let pipe = std::fs::File::from(std::os::fd::OwnedFd::from(reader));
    let meta = pipe
        .metadata()
        .map_err(|e| format!("cannot read a pipe: {e}"))?;
    Ok(meta.uid())
}

No use line changes: MetadataExt (for .uid()) is already imported, and the rest is named in full.

Steps

  • 1. Create .cargo/config.toml, then copy the test: cp docs/plans/M5a/files/crates/toolkit/tests/shell.rs crates/toolkit/tests/
  • 2. Make the three edits to secrets.rs. Run cargo fmt --all.
  • 3. Run the tests. cargo test -p gatewayd -p toolkit -p brokerd: every suite passes.
  • 4. Run the gate. make gate. Expected last line: gate: ok, with 936 tests, the same as before this task. On macOS it failed before this task, with 8 tests failing; now it passes.
  • 5. Log and commit. git add .cargo/config.toml crates/gatewayd crates/toolkit docs/implementer-log.md && git commit

Done when

  • make gate prints gate: ok with 936 tests.

Stop and report if

  • Any line quoted above is not in the file exactly as shown.
  • cargo-deny is missing (error: no such command: deny): report it, do not install anything.
  • Any test fails after the changes. Do not change a test.