Skip to content

Isolated test boundary: compile-time test prefix + ephemeral macOS CI #3

Description

@djbclark

Why

Development keeps having to touch /usr/local's operational, load-bearing
boundary to test anything privileged. That is how this session accidentally
crossed the live sudo path twice while running a conformance case (see #2).
The installed broker is shared infrastructure other agents call constantly; it
must stop being the test target.

Decided 2026-08-18: do both of the following. A macOS VM was considered and
rejected — no Parallels licence, and this machine runs out of disk weekly.

Part A — compile-time test prefix, same machine

Install a second, parallel boundary at a non-standard prefix with its own
service identity, and point development at that.

Already parameterized: install accepts --vault, --service-user,
--service-group, --operator.

The one blocker is sudo-secretspec-cli/src/main.rs:20:

const CONFIG_PATH: &str = "/usr/local/etc/sudo-secretspec.toml";

It is hardcoded on purpose. If a caller could redirect the config it could
redirect the vault path and the service user, which is a straightforward
privilege-escalation vector. So:

  • Do NOT add a runtime environment override to shipped builds. Gate it
    behind a cargo feature (test-boundary, default = []) so a release
    binary does not contain the code path at all, rather than containing it
    and declining to use it.
  • Add a release-artifact check asserting the feature is off, so the gate
    cannot be defeated by a stray --features in a build job.
  • Stand up the test boundary: prefix /opt/sudo-secretspec-test, service
    user _sudo_secretspec_test, vault under the same prefix. The prefix must
    be root-owned and non-group-writable at every level or drift.rs
    check_ancestor_chain will (correctly) refuse it.
  • Two sudoers policies will now exist on the live machine. Confirm
    uninstall of one cannot remove the other. There is already a test named
    uninstall_never_removes_a_policy_it_cannot_prove_it_wrote, so the
    provenance machinery exists — verify it covers this case rather than
    assuming it does.
  • Refuse cross-wiring: a binary built with the test feature must not operate
    the production prefix, and a production binary must not operate the test
    prefix. Failing closed here is the whole point.

Part B — ephemeral macOS CI

  • Add a workflow running the full lifecycle — install → declare → set → get
    → drift → rollback → uninstall → --purge-vault — on a fresh
    macos-latest runner. A throwaway machine is the only place it is safe to
    exercise the destructive paths honestly.
  • Use synthetic secrets only. Nothing from the real vault.

Guardrails to preserve

The 229 cargo test -p sudo-secretspec-cli tests already run hermetically
against tempdirs and never touch the live boundary. Keep it that way — Part A is
for the things a unit test genuinely cannot cover (real sudo, real dscl
identities, real sudoers parsing), not a replacement for them.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions