feat(build): add os-package native add-on template (#3425) #3471

Merged
mfreeman451 merged 1 commit from feat/addon-os-package-template into staging 2026-05-31 16:55:25 +00:00
Owner

What

delivery-models task 1.2 (os-package half) — the os-package add-on template. Companion to the per-arch pushed-artifact tarball (#3470); together they complete 1.2 within this change's scope.

An os-package add-on is delivered as a deb/rpm rather than a signed pushed-artifact tarball. This PR codifies that contract as an inert, copy-ready scaffold at build/packaging/addon-template/.

The contract (documented in the README)

  • Depends on serviceradar-agent (deb_depends / rpm_requires) — governed by the agent, meaningless without it.
  • Dormant on install. The package installs the binary, manifest, config, and systemd unit(s), but the post-install script never enables or starts anything. The agent activates the add-on (enables the unit / launches the on-host binary as a go-plugin) only when it is enabled for that agent in Edge Ops — so package presence never bypasses per-agent targeting/approval. Pre-remove stops + disables.
  • Standard install paths so the agent finds the binary via the manifest's exec.install_path + exec.binary; ships the self-describing addon.yaml so the on-host package is verifiable against the catalog.
  • Covers the systemd-timer (default, Bumblebee model), systemd-service, and agent-sidecar supervision variants.

Contents

build/packaging/addon-template/
  README.md            # contract + copy-ready packages.bzl & BUILD.bazel snippets
  addon.yaml           # delivery: os-package manifest
  config.schema.json   # source-side schema referenced by addon.yaml
  config/serviceradar-addon-example.json
  systemd/serviceradar-addon-example.service   # hardened Type=oneshot
  systemd/serviceradar-addon-example.timer
  scripts/postinstall.sh   # DORMANT: create user/dirs + daemon-reload, never enable
  scripts/preremove.sh     # stop + disable

Why inert (no BUILD.bazel / no PACKAGES entry)

release_targets.bzl's declare_release_artifacts() builds a _deb/_rpm for every PACKAGES key, so any real entry is auto-released. A "sample" os-package add-on would therefore ship as a real release artifact — not wanted. The scaffold deliberately has no BUILD.bazel and no PACKAGES entry, so it is neither built nor released and cannot break CI; it is the source you copy to package a real os-package add-on (netprobe, bumblebee). build/packaging/bumblebee-scan remains the shipping reference instance (os-package + systemd-timer).

Verification

sh -n clean on both scripts; config + config.schema.json parse as JSON; openspec validate add-native-addon-delivery-models --strict passes. tasks.md updated — 1.2 done within delivery-models (signing owned by build-signing, secret-blocked); only the breaking base-agent carve (1.1) remains.

🤖 Generated with Claude Code

## What delivery-models **task 1.2 (os-package half)** — the `os-package` add-on template. Companion to the per-arch pushed-artifact tarball (#3470); together they complete 1.2 within this change's scope. An `os-package` add-on is delivered as a deb/rpm rather than a signed pushed-artifact tarball. This PR codifies that contract as an inert, copy-ready scaffold at `build/packaging/addon-template/`. ## The contract (documented in the README) - **Depends on `serviceradar-agent`** (`deb_depends` / `rpm_requires`) — governed by the agent, meaningless without it. - **Dormant on install.** The package installs the binary, manifest, config, and systemd unit(s), but the post-install script **never enables or starts** anything. The agent activates the add-on (enables the unit / launches the on-host binary as a go-plugin) only when it is enabled for that agent in Edge Ops — so package presence never bypasses per-agent targeting/approval. Pre-remove stops + disables. - **Standard install paths** so the agent finds the binary via the manifest's `exec.install_path` + `exec.binary`; ships the self-describing `addon.yaml` so the on-host package is verifiable against the catalog. - Covers the **systemd-timer** (default, Bumblebee model), **systemd-service**, and **agent-sidecar** supervision variants. ## Contents ``` build/packaging/addon-template/ README.md # contract + copy-ready packages.bzl & BUILD.bazel snippets addon.yaml # delivery: os-package manifest config.schema.json # source-side schema referenced by addon.yaml config/serviceradar-addon-example.json systemd/serviceradar-addon-example.service # hardened Type=oneshot systemd/serviceradar-addon-example.timer scripts/postinstall.sh # DORMANT: create user/dirs + daemon-reload, never enable scripts/preremove.sh # stop + disable ``` ## Why inert (no BUILD.bazel / no PACKAGES entry) `release_targets.bzl`'s `declare_release_artifacts()` builds a `_deb`/`_rpm` for **every** `PACKAGES` key, so any real entry is auto-released. A "sample" os-package add-on would therefore ship as a real release artifact — not wanted. The scaffold deliberately has no `BUILD.bazel` and no `PACKAGES` entry, so it is neither built nor released and cannot break CI; it is the source you copy to package a real os-package add-on (netprobe, bumblebee). [`build/packaging/bumblebee-scan`](https://code.carverauto.dev/carverauto/serviceradar/src/branch/staging/build/packaging/bumblebee-scan) remains the shipping reference instance (os-package + systemd-timer). ## Verification `sh -n` clean on both scripts; config + config.schema.json parse as JSON; `openspec validate add-native-addon-delivery-models --strict` passes. tasks.md updated — 1.2 done within delivery-models (signing owned by build-signing, secret-blocked); only the breaking base-agent carve (1.1) remains. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(build): add os-package native add-on template (#3425)
Some checks failed
Secret Scan / gitleaks (pull_request) Successful in 21s
lint / lint (push) Successful in 1m8s
lint / lint (pull_request) Successful in 1m0s
Golang Tests / test-go (push) Successful in 1m24s
CI / build (pull_request) Failing after 2m32s
467c9f2c3a
delivery-models task 1.2 (os-package half). Codifies the os-package add-on
contract as an inert, copy-ready scaffold under build/packaging/addon-template/:

- README documents the contract — Depends serviceradar-agent; DORMANT on install
  (units shipped but postinst never enables them; the agent activates per its
  supervision model when the add-on is enabled in Edge Ops, never the package
  manager); standard install paths; ships the self-describing addon.yaml — with
  copy-ready packages.bzl + BUILD.bazel snippets and the systemd-timer /
  systemd-service / agent-sidecar supervision variants.
- Template files: addon.yaml (delivery: os-package), config + config.schema.json,
  hardened oneshot .service + .timer, and dormant postinstall/preremove scripts
  modeled on the shipping bumblebee-scan reference instance.

Inert by design: no BUILD.bazel and no PACKAGES entry, so it is not built or
released (declare_release_artifacts() iterates PACKAGES keys) and cannot break
CI; it is the source to copy when packaging a real os-package add-on (netprobe,
bumblebee). bumblebee-scan remains the shipping reference (os-package +
systemd-timer).

Within delivery-models, 1.2 is complete (tarball format + production landed in
#3470; os-package template here). Cryptographic signing/publishing of the
artifact is owned by add-native-addon-build-signing (secret-blocked). Only the
breaking base-agent carve (1.1) remains.

sh -n on both scripts + JSON parse clean; openspec --strict passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mfreeman451 left a comment

lgtm

lgtm
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!3471
No description provided.