feat(build): ship netprobe systemd-service unit in the add-on bundle (#3425) #3481

Merged
mfreeman451 merged 1 commit from feat/netprobe-systemd-unit into staging 2026-06-01 01:31:09 +00:00
Owner

Summary

migrate-netprobe-to-native-addon §1.3 — ships the netprobe systemd-service unit in the signed pushed-artifact bundle and resolves the standalone-vs-agent-launched open question to systemd-service.

Why systemd-service (the open question, resolved from the code)

  • netprobe binds its own IPC socket (rust/netprobe/src/server.rs UnixListener::bind) and the agent connects as a client (go/pkg/agent/netprobe/client.go Dial).
  • --config is optional: netprobe starts with its lifecycle IPC available and stays disabled until configured over IPC (main.rs).

So the migration keeps the existing config-over-IPC + ingest path unchanged; the only thing that moves is process supervision — from the agent's sidecar manager to systemd. The manifest already declared supervision: systemd-service; this makes it real.

What's in the bundle

  • addons/netprobe/serviceradar-netprobe.service — runs as User=serviceradar (manifest requires.run_as) with CAP_NET_RAW/CAP_BPF/CAP_PERFMON granted ambient + bounded. eBPF-hostile hardening (MemoryDenyWriteExecute, SystemCallFilter=~@privileged, PrivateDevices) is deliberately omitted; ExecStart runs --socket /run/serviceradar/netprobe/ipc.sock with no --config.
  • The unit installs verbatim (InstallAddonSystemdUnits — no ExecStart templating), so its ExecStart hardcodes the fixed staged path /var/lib/serviceradar/agent/addons/netprobe/current/serviceradar-netprobe. A Go contract test (netprobe_systemd_unit_test.go) pins that path to resolveAddonArtifactRoot so the unit and the staging layout can't drift apart.
  • Wired into the bundle via unit_entries (the defs.bzl plumbing already mapped these to the assembler's --entry); the unit rides flat at 0644 in each per-arch tarball, next to the binary, where the agent's discoverStagedAddonUnits finds it.

Scope / safety

The unit is inert until §2.2 wires assignment-gated activation (today netprobe is still started by the always-on applyVisibilityConfig sidecar path). Final hardening is locked in by the §4.3 scratch-agent e2e — native bundles cross-compile + run on Linux only, so the unit's runtime behavior is validated there, not on this host.

Validation

  • addon-manifest-validator addons/netprobe/addon.yamlOK
  • Assembler emits serviceradar-netprobe.service flat at 0644 in the per-arch tarball (alongside the 0755 binary)
  • bazel query loads //addons/netprobe (:netprobe_systemd_unit resolves) and the 6 netprobe_addon_bundle* targets with the new unit_entries
  • Go contract test passes; gofmt clean
  • openspec validate migrate-netprobe-to-native-addon --strict → valid

Follow-ups (migrate-netprobe §2.x)

  • §2.1/§2.2: assignment-gated install/enable of the unit via the agent-updater + connect-as-client, replacing the always-on applyVisibilityConfig sidecar path
  • §2.3 status, §2.4 rollback, §4.x tests (incl. the §4.3 scratch-Linux-agent e2e)

🤖 Generated with Claude Code

## Summary `migrate-netprobe-to-native-addon` §1.3 — ships the netprobe **systemd-service unit** in the signed pushed-artifact bundle and **resolves the standalone-vs-agent-launched open question** to `systemd-service`. ### Why systemd-service (the open question, resolved from the code) - netprobe **binds its own IPC socket** (`rust/netprobe/src/server.rs` `UnixListener::bind`) and the agent connects as a **client** (`go/pkg/agent/netprobe/client.go` `Dial`). - `--config` is **optional**: netprobe starts with its lifecycle IPC available and stays disabled until configured over IPC (`main.rs`). So the migration keeps the existing **config-over-IPC + ingest** path unchanged; the only thing that moves is **process supervision** — from the agent's sidecar manager to systemd. The manifest already declared `supervision: systemd-service`; this makes it real. ### What's in the bundle - **`addons/netprobe/serviceradar-netprobe.service`** — runs as `User=serviceradar` (manifest `requires.run_as`) with `CAP_NET_RAW`/`CAP_BPF`/`CAP_PERFMON` granted ambient + bounded. eBPF-hostile hardening (`MemoryDenyWriteExecute`, `SystemCallFilter=~@privileged`, `PrivateDevices`) is deliberately omitted; `ExecStart` runs `--socket /run/serviceradar/netprobe/ipc.sock` with no `--config`. - The unit installs **verbatim** (`InstallAddonSystemdUnits` — no `ExecStart` templating), so its `ExecStart` hardcodes the fixed staged path `/var/lib/serviceradar/agent/addons/netprobe/current/serviceradar-netprobe`. A **Go contract test** (`netprobe_systemd_unit_test.go`) pins that path to `resolveAddonArtifactRoot` so the unit and the staging layout can't drift apart. - Wired into the bundle via **`unit_entries`** (the `defs.bzl` plumbing already mapped these to the assembler's `--entry`); the unit rides **flat at 0644** in each per-arch tarball, next to the binary, where the agent's `discoverStagedAddonUnits` finds it. ### Scope / safety The unit is **inert until §2.2** wires assignment-gated activation (today netprobe is still started by the always-on `applyVisibilityConfig` sidecar path). Final hardening is locked in by the §4.3 scratch-agent e2e — native bundles cross-compile + run on Linux only, so the unit's runtime behavior is validated there, not on this host. ## Validation - `addon-manifest-validator addons/netprobe/addon.yaml` → `OK` - Assembler emits `serviceradar-netprobe.service` **flat at 0644** in the per-arch tarball (alongside the 0755 binary) - `bazel query` loads `//addons/netprobe` (`:netprobe_systemd_unit` resolves) and the 6 `netprobe_addon_bundle*` targets with the new `unit_entries` - Go contract test passes; `gofmt` clean - `openspec validate migrate-netprobe-to-native-addon --strict` → valid ## Follow-ups (migrate-netprobe §2.x) - §2.1/§2.2: assignment-gated install/enable of the unit via the agent-updater + connect-as-client, replacing the always-on `applyVisibilityConfig` sidecar path - §2.3 status, §2.4 rollback, §4.x tests (incl. the §4.3 scratch-Linux-agent e2e) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(build): ship netprobe systemd-service unit in the add-on bundle (#3425)
Some checks failed
Secret Scan / gitleaks (pull_request) Successful in 27s
lint / lint (pull_request) Successful in 1m22s
lint / lint (push) Successful in 1m45s
Golang Tests / test-go (push) Successful in 2m16s
CI / build (pull_request) Failing after 4m37s
ed9661282b
migrate-netprobe-to-native-addon §1.3. Resolves the standalone-vs-agent-launched
socket-lifecycle open question to systemd-service and ships the unit.

The code coupling settles the open question: netprobe binds its own IPC socket
(rust/netprobe/src/server.rs UnixListener::bind) and the agent connects as a client
(go/pkg/agent/netprobe/client.go Dial); --config is optional, so netprobe starts with
its lifecycle IPC available and stays disabled until configured over IPC. So the
migration keeps the existing config-over-IPC + ingest path and only moves process
supervision from the agent's sidecar manager to systemd.

- addons/netprobe/serviceradar-netprobe.service: the systemd-service unit. Runs as
  User=serviceradar (requires.run_as) with the manifest's CAP_NET_RAW/CAP_BPF/CAP_PERFMON
  granted ambient + bounded; eBPF-hostile hardening (MemoryDenyWriteExecute,
  SystemCallFilter=~@privileged, PrivateDevices) is deliberately omitted. ExecStart runs
  the binary with --socket /run/serviceradar/netprobe/ipc.sock and no --config.
- The unit installs verbatim (InstallAddonSystemdUnits, no ExecStart templating), so its
  ExecStart hardcodes the fixed staged path
  /var/lib/serviceradar/agent/addons/netprobe/current/serviceradar-netprobe. A Go contract
  test (netprobe_systemd_unit_test.go) pins that path to resolveAddonArtifactRoot so the
  unit and the staging layout can't drift.
- Wired into the bundle via unit_entries (defs.bzl already maps these to assembler
  --entry); the unit rides flat at 0644 in each per-arch tarball next to the binary.

The unit is inert until §2.2 wires assignment-gated activation; final hardening is locked
by the §4.3 scratch-agent e2e (bundles cross-compile + run on linux only).

Validation: addon-manifest-validator OK; assembler emits the unit flat at 0644 in the
per-arch tarball; `bazel query` loads //addons/netprobe + the netprobe bundle targets with
unit_entries; the Go contract test passes; `openspec validate migrate-netprobe-to-native-addon
--strict` is clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mfreeman451 left a comment

lgtm

lgtm
mfreeman451 deleted branch feat/netprobe-systemd-unit 2026-06-01 01:31:09 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!3481
No description provided.