Skip to content

feat(server): Home Server integration (superseded by focused PRs) - #463

Closed
castrojo wants to merge 1 commit into
mainfrom
feat/home-server-20261011
Closed

castrojo wants to merge 1 commit into
mainfrom
feat/home-server-20261011

Conversation

@castrojo

@castrojo castrojo commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Superseded by focused replacements

Closed in favor of @jeefy's requested split; this original umbrella must not be merged. Replacement order:

  1. feat(runtimes): ship opt-in rootless Podman and Docker sysexts #484 — independent optional Podman/Docker sysexts, disabled units/features, signed assets and operator documentation.
  2. feat(homebrew): ship the transparent bridge as an opt-in sysext #485 — paired Brew machine + optional host-integration sysext, sudo/namespace boundary fixes and self-contained opt-in profiles. Stacked on feat(runtimes): ship opt-in rootless Podman and Docker sysexts #484 and draft pending producer merge.
  3. feat(installer): add Home Server as an explicit opt-in profile #486 — native USB owner/options/offline seeding as an explicit Home Server opt-in. Stacked on feat(homebrew): ship the transparent bridge as an opt-in sysext #485; minimal remains profile zero/default.

Review fixes

  • Actual base EROFS has no Brew/Python/helper/owner-service/sudoers hook; the bridge ships only in the selected integration sysext.
  • Native allowed/denied sudo audit events remain enabled. Package argv/environment use a sealed caller-owned request, outside sudo argv and scope descriptions.
  • Shared cwd identity is pinned and compared across host/guest; caller access is rechecked before execution. Authenticated active GID and NSS supplementary groups are preserved.
  • Rebased on current main including sed/gzip dependencies. Corrected stale action-tag comments without changing pinned action code; canonical Prow label synchronization and replacement PR standard checks passed.
  • feat(homebrew): ship the transparent bridge as an opt-in sysext #485/feat(installer): add Home Server as an explicit opt-in profile #486 carry full-build; their real build lanes are running, not silently skipped. Remote full-build/boot success is not yet claimed.

Completed local evidence

Actual x86_64 signed image build/export, standalone/overlaid ELF-program closure and final publication verification passed: 31 signed assets using local development keys. Clean final stacked head 6dbf211 has all 30 non-SBOM payloads byte-identical to the boot-tested release; only the SBOM digest changed.

Complete QEMU/Fedora-OVMF Secure Boot console install and both installed boots passed: dm-verity disk root, decoy disk untouched, locked root, nonroot owner login, SSH Brew install/update and persistence, detached tmux, rootless host Podman workloads via Brew clients, Compose and same-path mounts. Original helper/policy reproduced three expected failures; the corrected installed helper passed 29 real-machine behavior cases without skips. Optional Docker-daemon boot is not claimed by this run.

External prerequisite — still blocked

fsdk-containers#436 must receive independent approval and merge first. #485 explicitly uses tested review SHA ae5bf888b72693bb6774cd56d21da4677efc2e36 and its matching branch track. Re-pin to the actual merged main SHA/track and rerun native gates before shipping. No main merge commit was invented and no approval or merge bypassed. Docker's upstream-static policy remains a maintainer decision in #484; independent sudo/namespace review remains required for #485.

Replacement PRs contain current verification/CI status. Earlier claims in this umbrella's edit history are historical, not evidence for the new heads.

Ship a persistent FSDK nspawn Homebrew machine with private nonroot owner provisioning, complete command dispatch and optional rootless host OCI engines. Preserve native installation, signed release updates and optional canonical Homelab/KubeStellar integration.

Verify the installed console/SSH/reboot path, real host engine workloads, all nine machine regressions and nine descriptor/job-control/privacy edge cases. Record seeding, loader and orderly lifecycle invariants in the routed skills.

Assisted-by: github-copilot/gpt-6.1-sol via GitHub Copilot

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hivecommons-hive

Copy link
Copy Markdown
Contributor
474afc4

ℹ️ Sentinel notice — informational; author is trusted (owner), merge is not blocked

Hive flagged this PR (author @castrojo, head 474afc423a3a) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 2 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • .github/workflows/reproducibility.yml
    • Justfile
  • remote_code_execution — adds a remote-fetch-and-execute, decoded payload, reverse shell or embedded credential (Adds curl|sh, eval of encoded payloads, reverse shells or embedded private keys)
    • tests/unit/test_homebrew_dispatch_edges.py

Hive did not add the sentinel-alert label because this author is trusted. The finding remains recorded for audit and the dashboard Security tab; set sentinel.trusted_authors_block: true to require the blocking label for trusted authors too.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Routing to a human: this needs a maintainer with sudo/namespace security background, and it is blocked on fsdk-containers#436.

I read the privileged path (files/homebrew/dispatch.c, files/homebrew/bluefin-homebrew.sudoers, files/os/ssh/sshd_config.d/bluefin-server.conf) rather than the whole 95-file / +4000-line diff. I did not find a defect in what I read, but the trust decision here is not one this lane should make.

What the change actually grants (verified, not from the body)

  • files/homebrew/bluefin-homebrew.sudoers:4 — ALL ALL=(root) NOPASSWD: /usr/libexec/bluefin-homebrew-enter. Every local account on the server image gets passwordless root execution of this helper. The helper, not sudoers, is the only thing standing between any user and root.
  • :10 — Defaults!… !log_allowed disables sudo's allowed-command logging for that rule. The comment justifies it (argv may contain tokens), and argv is in fact moved out of the sudo command line into a sealed memfd (dispatch.c launch()), but it still means successful root invocations by any user leave no sudo log. That is a deliberate audit trade-off a maintainer should sign off on explicitly.
  • dispatch.c helper(): requires real uid 0, SUDO_UID/GID must match a passwd entry (number() rejects 0 and ≥65534), cwd must be absolute, physical and under a root listed in root-owned /run/bluefin-homebrew/roots for that uid (authorize_cwd), the request memfd must be owned by the caller and carry WRITE|GROW|SHRINK|SEAL seals (read_environment), and brew itself is restricted to the uid in /var/lib/bluefin-homebrew/owner. pin_machine() verifies the machine leader's cgroup is …/bluefin-homebrew.service/payload/… on a unified hierarchy before opening its /proc/<pid>/{root,ns/*}, then polls the pidfd to confirm the leader did not exit mid-pin.
  • enter(): root work is limited to cgroup placement, setns() over the pre-pinned fds (user ns last), chroot, optional mount_setattr(RDONLY) of the prefix for non-owners, then drop_privileges() (bounding set, setresgid/uid, capset to zero, NO_NEW_PRIVS, ambient clear) before clearenv() / caller env is installed / execv("/usr/bin/systemd-run --user --scope … bash -p …"). LD_PRELOAD/LD_LIBRARY_PATH/LD_AUDIT are stripped. The ordering is right: nothing caller-controlled is interpreted while privileged.
  • sshd_config.d/bluefin-server.conf — SetEnv PATH=/usr/bin:/bin:/usr/sbin:/sbin:/var/lib/bluefin-homebrew/commands puts the root-owned shim dir last in PATH for non-login SSH commands; Subsystem sftp internal-sftp.

Open questions for the human reviewer (not findings — I could not verify these without the image)

  1. authorize_cwd() runs realpath() against the host view of cwd, then enter() does chdir(cwd) after chroot into the guest root. The design assumes the authorized roots are bind-mounted at identical paths inside the machine ("same-path project mounts" per the body). If any authorized root is reachable on the host but mounted differently in the guest, the check and the use diverge. Worth a maintainer confirming the roots file is only ever populated with same-path mounts.
  2. drop_privileges() calls setgroups() with the host supplementary group list after setns() into the machine's user namespace. If the nspawn machine uses --private-users, those gids may not map. The tests in tests/unit/test_homebrew_dispatch*.py may already cover this; I did not read them.

Scope

The PR also bundles podman/docker sysexts, sysupdate transfers, installer services, release-publishing changes and a 2-arch check-image.py rewrite. The body (correctly) says it depends on fsdk-containers#436, which is itself currently awaiting a human in the hive queue. The eight full-image/boot checks on this PR are all SKIPPED, so nothing here has been built in CI on this head.

Recommendation: do not merge until fsdk-containers#436 lands and a maintainer has explicitly accepted (a) all-users NOPASSWD root into the helper and (b) !log_allowed. I have not approved or changed anything.

Confidence: 1/5 (needs attention) — 1 high finding; 2 medium findings

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@jeefy jeefy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the C is more careful than most setuid-style helpers (O_NOFOLLOW on trusted files, capset→0 + NO_NEW_PRIVS, clearenv + LD_* scrub, --expand-environment=no, read-only prefix for non-owners, strict argv shape). The requested changes are about packaging and trust boundaries, not code quality.

Requested changes

  1. Pin fsdk-containers to a commit on its main. elements/fsdk-containers.bst pins d75f216e… from the still-open fsdk-containers#436 with track: main. If #436 is squashed that SHA becomes unreachable and the build breaks; the junction tracker would also "bump" it to main and silently drop the brew image. Land #436 first, then re-pin here.

  2. Move the sudo bridge out of base /usr. elements/bluefin-server/os-stack.bst adds homebrew/dispatch.bst, so ALL ALL=(root) NOPASSWD: /usr/libexec/bluefin-homebrew-enter ships in every install, including "Advanced minimal". Ship dispatch.bst (helper, sudoers drop-in, units) in the homebrew sysext / image-integration so the rule exists only where the machine does.

  3. Keep sudo logging on. Defaults!… !log_allowed removes the audit trail for successful root invocations by any local user. Brew argv carrying tokens is a real concern, but drop the arguments, not the event — e.g. Defaults!/usr/libexec/bluefin-homebrew-enter !log_args (or redact in the helper and log the sanitized command).

  4. Make the host→guest cwd mapping explicit. authorize_cwd() (dispatch.c:105-128) resolves and authorizes cwd against /run/bluefin-homebrew/roots in the host namespace, then enter() does chdir(cwd) at :479 inside the guest root after chroot. That is only sound if every authorized root is bind-mounted at the identical path in the machine. That guarantee lives in the fsdk-containers image, not here. Either verify it in the helper (e.g. compare st_dev/st_ino of the host-resolved cwd with the guest path after entering, before dropping privileges) or document the invariant in dispatch.c and in the fsdk-containers image recipe, with a test.

  5. Split the PR. Suggested order, each independently mergeable:

    • runtimes: Podman/Docker sysexts + sysupdate transfers + disable presets (fits existing sysext policy as-is);
    • homebrew: machine image transfer + bridge (after 1–4), with the full-build label so CI actually boots it — all image/boot jobs were skipped on this PR and the body notes the coexistence replay never completed;
    • installer default: the one-line menu change, last.
  6. Rebase — currently DIRTY against main (sed/gzip build-depends landed in bluefin-server-image.bst).

Maintainer decisions (not blockers for the above)

  • Should Home Server be the default installer entry? It makes rootless Podman default-on for the default install, which bends "container runtimes are opt-in, no preset enables them".
  • Are Docker's upstream static binaries acceptable in a sysext under the k0s/kubeadm precedent?

Happy to re-review the split PRs quickly.

@castrojo castrojo changed the title feat(server): add transparent Homebrew Home Server profile feat(server): Home Server integration (superseded by focused PRs) Oct 17, 2026
@castrojo
castrojo marked this pull request as draft October 17, 2026 02:21
@castrojo castrojo closed this Oct 17, 2026
@castrojo

Copy link
Copy Markdown
Contributor Author

@jeefy the requested split is published: #484 (independent runtimes), #485 (opt-in Brew integration), #486 (opt-in native installer). This umbrella is closed as superseded, not merged.

The active-primary-GID/NSS-group defect, host/guest cwd identity/access defect and suppressed-sudo-audit defect are fixed. All three original failures reproduced against the old installed helper/policy; 29 actual installed-machine behavior cases passed without skips against the corrected helper. Complete QEMU/Fedora-OVMF Secure Boot console installation and both installed boots passed, including real SSH Brew updates, persistent packages, detached tmux and host Podman/Compose workloads. The clean final stack rebuilt; all 30 non-SBOM payloads match the boot-tested artifacts and final verification accepted all 31 signed assets using development keys.

Minimal is still default. The privileged bridge/Python closure is absent from the base OS and lives in the selected integration sysext. Standard current-head checks passed; #485/#486 have full-build and their real builds are running, so remote build/boot success is not claimed yet. The optional Docker daemon was not boot-tested in this run.

Independent producer approval/merge for fsdk-containers#436 remains required before replacing #485's explicitly identified review pin with the actual main SHA/track. #485/#486 remain draft; no approval or merge bypassed. Docker's upstream-static policy decision is isolated in #484, and sudo/namespace review remains explicit in #485.

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.

2 participants