8000 feat(minzoned,minvmd,minimal): one box-name service for a Mac's users, admitting a group by bryan-minimal · Pull Request #2976 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(minzoned,minvmd,minimal): one box-name service for a Mac's users, admitting a group - #2976

Draft
bryan-minimal wants to merge 2 commits into
pr1/system-image-dirsfrom
pr2/shared-box-name-service
Draft

bryan-minimal wants to merge 2 commits into
pr1/system-image-dirsfrom
pr2/shared-box-name-service

Conversation

@bryan-minimal
@bryan-minimal bryan-minimal commented Nov 4, 2026 •
Copy link
Copy Markdown
Member

minzoned --admit-group GROUP: the installed service admits, besides its
own uid, root and every member of the group, judged on the peer's uid
from the kernel before a byte of it is read (getgrouplist, the primary
group and every supplementary one, with the buffer grown on truncation).
A node is the hello's node id qualified with that uid, so another user
speaking the same id is another node: nobody can replace or release
another user's rows by naming their daemon, a clash between them is the
ordinary first-publisher clash with the holder named, uid included, and
the service keeps no state across a restart. The refusal a non-member
reads names their account and the one command that admits them.

min finalize-install --show knows such a shared service: the unit's
--admit-group, the socket expected to be the group's (0660, the group's
write bit) and the service account's, not the operator's; an operator
outside the group is told the way in. The step never replaces the shared
service, for a member or root either: over a custody failure or a protocol
mismatch it is unavailable, with the package that installed the service
named as the remedy, and --undo is refused over a unit that admits a
group. With no user daemon reporting a port, the names item judges by the
port the host's resolver hook names, when the service answers there.

The macOS system package (next) runs the service this way under a role
account. Spec 18's open question on several users of one host, option 2.

Context

Second of three stacked PRs for the macOS system install (gominimal/inbox#1179), on top of #2975. Spec 18 (docs/specs/18-spec-box-networking.md) leaves the question of several users of one host open and lists the options; this is option 2: one box-name service for the Mac, admitting a group, with a node keyed by its id and the peer's uid. The per-user service's single-uid rule is unchanged; nothing changes on Linux.

Proof

Three review rounds on the minfarm found and fixed, in order: a bindings file (removed; the pair keying replaced it), a takeover through finalize-install by a group member, the ERANGE handling, the refusal wording, the mode check. The design, probes and rounds are in the farm's docs/research/box-name-service-users.md (gominimal/minfarm). minimal's Linux PR gates reproduced on the farm's Linux lane (the first run caught a getgrouplist buffer type that is int on macOS and gid_t on Linux); minvmd's tests on macOS (685); the lab prepush on anvil.

The pre-PR review (2026-11-04), settled in the second commit

The four things the read found, and the smaller ones, are in 5f8f7cb6:

  1. Membership is judged off the accept loop. The loop judges only what needs no lookup: the service's own uid, root on the shared service, and every peer of a single-operator answerer. A group member is judged on the connection's own thread, so a directory service's seconds stall that connection alone. On macOS membership asks mbr_check_membership (nested groups, more than sixteen), with getgrouplist behind it. The admission test reads the account's groups, not the process's, and holds under root.
  2. The guards fail closed. A unit file that exists but is not text (a binary plist, an unreadable file) makes --show offer nothing and --undo refuse, both naming the file and the plutil line that reopens it. --admit-group is read from the unit's program arguments (the plist's ProgramArguments array, the unit's ExecStart=), not from anywhere in the file.
  3. A released name stays its user's. A box name is its first publisher's while its row is up and for the answer TTL after it goes, the quarantine an address has, so a daemon restart or a laptop's sleep never loses a name to another member and a cached answer never reaches another user's box. The service remembers nothing across its own restart; that window is the group's trust, and spec 18 now says so (the open question carries the option taken). A refusal names another user's node by uid, never by its state directory.
  4. Each user is capped on the shared service: 32 open channel connections, a quarter of the box range. A single-operator answerer caps nothing. The add-to-group line is the service's, by platform, so the channel and --show agree.

Proof of the second commit

  • The farm's Linux lane (minimal's own cargo nextest run -p minimal --lib in a box): 702 passed, 1 skipped (j-4f06879a0ed6efb6).
  • cargo nextest run -p minvmd --lib on a Mac: 689 passed. Clippy clean on the three crates.
  • A package Mac (macOS 27 VM, the stacked package built from this commit, j-942fa53eecc240e9): a non-member's refusal names them by account and uid and ends with the dseditgroup line; a member published a name and went, root was refused it (another user's node (uid 501) released this name less than 15 s ago; it stays theirs for 14 s more), the member took it straight back; the 33rd connection of one user was refused with the count and the 32nd served; plutil -convert binary1 on the plist made --show and --undo refuse naming the file, exit 1, and xml1 reopened them. The package journey itself passed on the same build (j-dfb7a945fce76e81).

Still to decide, not code: the package README's open questions (#2977).

🤖 Generated with Claude Code

…, admitting a group

`minzoned --admit-group GROUP`: the installed service admits, besides its
own uid, root and every member of the group, judged on the peer's uid
from the kernel before a byte of it is read (getgrouplist, the primary
group and every supplementary one, with the buffer grown on truncation).
A node is the hello's node id qualified with that uid, so another user
speaking the same id is another node: nobody can replace or release
another user's rows by naming their daemon, a clash between them is the
ordinary first-publisher clash with the holder named, uid included, and
the service keeps no state across a restart. The refusal a non-member
reads names their account and the one command that admits them.

`min finalize-install --show` knows such a shared service: the unit's
`--admit-group`, the socket expected to be the group's (0660, the group's
write bit) and the service account's, not the operator's; an operator
outside the group is told the way in. The step never replaces the shared
service, for a member or root either: over a custody failure or a protocol
mismatch it is unavailable, with the package that installed the service
named as the remedy, and `--undo` is refused over a unit that admits a
group. With no user daemon reporting a port, the names item judges by the
port the host's resolver hook names, when the service answers there.

The macOS system package (next) runs the service this way under a role
account. Spec 18's open question on several users of one host, option 2.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai
coderabbitai Bot commented Nov 4, 2026
Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@bryan-minimal
Copy link
Copy Markdown
Member Author

Lab prepush on anvil for this commit (6a4e81c on PR 1; job 01828, CI's commands on the box): fmt, clippy -D warnings on Linux, the workspace tests (minvmd's admission and node-key tests included), the new tests repeated, doctests and the native daemon e2e all pass; mr ci passes except cargo-machete, which is main's unused camino in minimal-client (#2872). The root-integration and KVM lanes are not run on the box. The review items in the description stand.

…caps each user, keeps a released name theirs

The four things the pre-PR read of #2976 found, and the smaller ones:

- A group member is judged on the connection's own thread; the accept loop
  judges only what needs no lookup (the own uid, root, every peer of a
  single-operator answerer). On macOS membership asks the membership API
  (nested groups, more than sixteen groups), with getgrouplist behind it.
- The shared service caps each user: 32 open channel connections, a quarter
  of the box range. A single-operator answerer caps nothing.
- A box name stays its last user's for the answer TTL after its row goes,
  as an address does, so a reconnect never loses a name to another member.
  Across a service restart nothing is remembered; spec 18 says so.
- The CLI's `--undo` and reinstall guards fail closed on a unit file that is
  there but not text (a binary plist, an unreadable file), naming the file.
- `--admit-group` is read from the unit's program arguments, not anywhere
  in the file. A refusal names another user's node by uid, never by its
  state directory. The add-to-group line is the service's, by platform.
- The admission test reads the account's groups, not the process's, and
  holds under root. Misplaced doc comments sit on their items.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions
github-actions Bot commented Nov 5, 2026
Copy link
Copy Markdown
Contributor

Spec lint

docs/specs/18-spec-box-networking/18-spec-box-networking.md — 17 finding(s)

docs/specs/18-spec-box-networking/18-spec-box-networking.md:171: P004 NET-009 names test 'native_resolution_without_proxy_env', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:378: P004 NET-040 names test 'fresh_install_own_ip_ingress_publishes_loopback', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:388: P004 NET-041 names test 'installer_switch_binary_executable', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:435: P004 NET-048 names test 'linux_amd64_manifest_ships_vm_stack', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:440: P004 NET-049 names test 'fresh_linux_kvm_activate_local_minvmd', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:445: P004 NET-050 names test 'linux_arm64_manifest_ships_vm_stack', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:450: P004 NET-051 names test 'fresh_arm64_kvm_activate_local_minvmd', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:634: P004 NET-163 names test 'zone_name_rule_admits_sibling_lease_under_its_ingress', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:752: P004 NET-156 names test 'host_alias_refused_outside_exposures_for_boxes', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:757: P004 NET-158 names test 'host_alias_admits_baseline_for_node_plane_only', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:762: P004 NET-159 names test 'host_exposures_read_from_client_config', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:772: P004 NET-160 names test 'native_own_ip_host_exposure_needs_the_box_to_name_the_host', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:782: P004 NET-161 names test 'native_own_ip_follows_the_current_host_exposures_table', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:792: P004 NET-162 names test 'host_exposure_on_minimal_listener_port_refused', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:893: P004 NET-132 names test 'proxy_sees_each_vm_box_by_its_switch_address', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:919: P004 NET-134 names test 'deny_all_box_reaches_proxy_and_no_other_host_port', which was not found in the repository
docs/specs/18-spec-box-networking/18-spec-box-networking.md:943: P004 NET-107 names test 'session_outbound_request', which was not found in the repository

Advisory. None of this blocks the merge; the review decides.

Advisory, and never a merge gate. Linter: gominimal/foundry@fb5932b8, spec format: How Minimal Writes Specs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0