Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

**As of:** 2026-06-11
**Current phase:** Phases 0–5 complete; on the Phase 6/7 horizon. The AX.25 v2.2 Data-Link engine (Phase 2) is conformance-complete — mod-8 **and mod-128** connected-mode data transfer, REJ/SREJ recovery, segmentation, Timer Recovery, all green against the conformance + property harnesses (the on-air 10 kB lossy bench loop, #214, is the one residual, gated on TNC hardware not code). KISS hardening (Phase 3), the node host (Phase 4 — `Packet.Node`/`Packet.Node.Core`, deployable `.deb`), and the React web control panel (Phase 5) are all shipped and **live on the lab** (`pdn.m0lte.uk`): NET/ROM L3+L4 + INP3 routing, beacons, and a complete auth story (TLS · refresh-token rotation · WebAuthn passkeys · over-RF sysop TOTP) reachable over a real trusted cert with passkeys working on phone + laptop. A 2026-06-10 correctness sweep reconciled the issue tracker (it had drifted well behind the code) — see §17. **Next:** Phase 6 (AGW/RHPv2 external app surfaces) or Phase 7 (apt-repo distribution + signed one-click update); the deferred link-tuner is parked in Phase 8; per-frame RSSI/SNR (Tait 8100/8200, #363) is the Phase 10 adaptive-RF seed.
**Latest amendment:** [§17 entry 2026-06-11 — **DAPPS bundle re-pinned to v0.34.0** — manifest now fetched from the release (the interim copy deleted, completing the 5b design); the release carries `DAPPS_ENV_MANAGED` + the node-derived callsign with SSID probe-walk, so enabling dapps on a pdn node is now zero-config](#17-amendment-log)
**Latest amendment:** [§17 entry 2026-06-11 — App packages: the supervisor injects **`PDN_NODE_CALLSIGN`**/`PDN_NODE_ALIAS` so an app can derive its identity from the host node (the an-app-lives-at-an-SSID-of-the-node-callsign convention; first consumer: DAPPS's `<nodecall>-7` default)](#17-amendment-log)
**Latest amendment:** [§17 entry 2026-06-11 — App platform **Slice 5b: DAPPS bundled with pdn, public interfaces only** — `packaging/dapps/pdn-app.yaml` (service: the **published release binary** + the rhpv2-bearer environment; ui: its dashboard proxied under `/apps/dapps/`; capabilities network+web; no session verb — DAPPS binds its own callsigns over RHP) staged by build-deb from the **pinned m0lte/dapps release v0.33.12** (per-RID sha256 pins; cached; a failed pin hard-fails, an unreachable release skips the package and still builds); manifest upstreamed as m0lte/dapps#148. First-start seeding documented (owner supplies `DAPPS_CALLSIGN` via the `apps:` override before first start; placeholder mode is benign). Deb 39.8→73.4 MB](#17-amendment-log)
**Latest amendment:** [§17 entry 2026-06-11 — App platform **Slice 5a: the app-package model** — `pdn-app.yaml` manifests **authored by the app** and discovered under `/usr/share/packetnet/apps` + `/var/lib/packetnet/apps`; **discovered = disabled until the owner enables** (the trust grant — an `apps:` override entry or the new control-panel toggle, which shows the manifest's declared capabilities before flipping); a **pdn-supervised `service:` lifecycle** (start/stop with enablement, SIGTERM→grace→kill-tree, backoff + crash-loop breaker → Faulted, `managed: external` escape hatch); `GET/POST /api/v1/apps/packages[...]` + the Manage-apps UI; WALL + LOBBY migrated to real packages (LOBBY's daemon now pdn-supervised — no more hand-run systemd unit). Contract: docs/app-packages.md. +91 tests; 725 Node + 22 web green](#17-amendment-log)
Expand Down Expand Up @@ -1057,6 +1058,10 @@ What changed, why, where to look for details.
```


### 2026-06-11 — DAPPS bundle re-pinned to v0.34.0 — manifest now fetched from the release

DAPPS bundle re-pinned to v0.34.0 — manifest now fetched from the release (the interim copy deleted, completing the 5b design); the release carries `DAPPS_ENV_MANAGED` + the node-derived callsign with SSID probe-walk, so enabling dapps on a pdn node is now zero-config. Mechanics: m0lte/dapps v0.34.0 is the first release shipping `pdn-app.yaml` as a release asset (version-stamped to the tag — the m0lte/dapps#148 upstreaming landing), so build-deb.sh now pins FOUR assets (the three per-RID binaries + the manifest, each sha256-pinned) and fetches the manifest through the same version-keyed cache/verify/skip machinery as the binaries (`dapps_fetch`: a fresh download failing its pin hard-fails; unreachable with no valid cache warns and skips the dapps package entirely — all-or-nothing, never a binary without its manifest or vice versa); `packaging/dapps/pdn-app.yaml` is deleted as the 5b design always intended. `ShippedManifestsTests` re-pointed at the cached release asset (`artifacts/cache/dapps-v<pin>-pdn-app.yaml`, the path derived from the script pin so the cache key always tracks it): the dapps tests are now `[SkippableFact]`s (skip with "run scripts/build-deb.sh first" when the cache is absent), assert version 0.34.0 + the new `DAPPS_ENV_MANAGED=true` deployment-managed env mode, keep the manifest↔script version-drift guard, and the catalog test split into an unconditional examples/ (wall+lobby) leg + a skippable full-shipped-layout leg staging the cached manifest under a temp `dapps/` dir. Zero-config story: `DAPPS_ENV_MANAGED` makes the manifest's env deployment-managed (re-applied every start, badged read-only in the dashboard), and DAPPS derives its identity from the injected `PDN_NODE_CALLSIGN` as `<nodecall>-7`, probe-walking to the next free SSID on a duplicate-socket refusal — no more must-set-`DAPPS_CALLSIGN`-before-first-enable wrinkle (an explicit `DAPPS_CALLSIGN` override still wins). Deb 73.3 MB; 729 Node tests green (9 ShippedManifests).

### 2026-06-11 — App packages: PDN_NODE_CALLSIGN/PDN_NODE_ALIAS injected into supervised services

A one-line widening of the package contract (docs/app-packages.md § The manifest): the service supervisor now injects the node's own identity (`PDN_NODE_CALLSIGN`, plus `PDN_NODE_ALIAS` when set) alongside the existing `PDN_APP_*`/`PDN_RHP_*` variables — so an app can derive its on-air identity per Tom's convention that an app lives at an SSID of the node callsign (the first consumer: DAPPS, which gains a `<nodecall>-<DAPPS_SSID>` default in m0lte/dapps' config-env-precedence PR, removing the must-set-DAPPS_CALLSIGN-before-first-enable wrinkle).
Expand Down
56 changes: 0 additions & 56 deletions packaging/dapps/pdn-app.yaml

This file was deleted.

85 changes: 50 additions & 35 deletions scripts/build-deb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,20 @@ esac

# DAPPS — the bundled store-and-forward messaging app (docs/app-packages.md
# § Distribution). Public interfaces only: we FETCH the published self-contained
# release binary from m0lte/dapps (never build from or vendor its source) and
# pin it by version + per-RID sha256. To bump: download each dapps-linux-* asset
# from the new release ONCE, sha256sum it, and update all four pins together
# (plus packaging/dapps/pdn-app.yaml's version — ShippedManifestsTests asserts
# the manifest tracks dapps_version).
dapps_version="v0.33.12"
# release binary AND its app-authored pdn-app.yaml manifest from the SAME
# m0lte/dapps release (never build from or vendor its source) and pin every
# asset by version + sha256. To bump: download all FOUR assets from the new
# release ONCE (dapps-linux-{x64,arm64,arm} + pdn-app.yaml), sha256sum them,
# and update dapps_version + the four pins together (ShippedManifestsTests
# asserts the cached release manifest tracks dapps_version).
dapps_version="v0.34.0"
case "$rid" in
linux-x64) dapps_sha256="5040b79d2bd11cebead93445bc4a12a89a597e403a0c2ec2a7401600b9e5a95d" ;;
linux-arm64) dapps_sha256="835c0691a450730b52b915d7610c10ba5203f85eb0fa67f7303f631c7d82d609" ;;
linux-arm) dapps_sha256="02812ff9afcaf89b46a3b8739dc5ba556a4f817a5aa3dfa9bb372b710c4a035e" ;;
linux-x64) dapps_sha256="74677abcaa29aa6300416b7741236a12a061d915629653ce3bef3001e78f3e3c" ;;
linux-arm64) dapps_sha256="89f18f9e2344ade06bae07957c4de00a97bcd03bd8d95a06e1a0353b7b390b6e" ;;
linux-arm) dapps_sha256="49ff594ec7b54250f836178571b19fed86252b65474c03f2e1e23690815c9ef6" ;;
esac
# The manifest is RID-independent: one asset, one pin, version-stamped to the tag.
dapps_manifest_sha256="fabbd5675386bf2e3532413089f61a4268d5798acf1aba7d4a8ae71ef27fc85e"

root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
proj="$root/src/Packet.Node/Packet.Node.csproj"
Expand Down Expand Up @@ -95,40 +98,52 @@ install -d "$stage/usr/share/packetnet/apps/lobby"
install -m 0644 "$root/examples/lobby/pdn-app.yaml" "$stage/usr/share/packetnet/apps/lobby/pdn-app.yaml"
install -m 0755 "$root/examples/lobby/lobby.py" "$stage/usr/share/packetnet/apps/lobby/lobby.py"
install -m 0644 "$root/examples/lobby/README.md" "$stage/usr/share/packetnet/apps/lobby/README.md"
# DAPPS — staged from the m0lte/dapps PUBLISHED release artifact (pins above; the
# "only public interfaces" rule — docs/app-packages.md § Distribution). The asset is
# cached in artifacts/cache and re-downloaded only when the cached file's hash no
# longer matches the pin. A downloaded file that fails the pin is a hard build error
# (wrong artifact / tampering — never package it). If the download fails AND no valid
# cache exists (network-less build), the dapps package is SKIPPED with a warning and
# the deb still builds: DAPPS is bundled, not load-bearing.
# DAPPS — staged from the m0lte/dapps PUBLISHED release: the per-RID binary AND the
# app-authored pdn-app.yaml manifest, both assets of the SAME pinned release (pins
# above; the "only public interfaces" rule — docs/app-packages.md § Distribution).
# Each asset is cached in artifacts/cache (key includes the version) and re-downloaded
# only when the cached file's hash no longer matches its pin. A downloaded file that
# fails its pin is a hard build error (wrong artifact / tampering — never package it).
# If a download fails AND no valid cache exists (network-less build), the dapps
# package is SKIPPED with a warning and the deb still builds — all-or-nothing: a
# binary is never staged without its manifest, nor a manifest without its binary.
# DAPPS is bundled, not load-bearing.
dapps_cache="$root/artifacts/cache/dapps-${dapps_version}-${rid}"
dapps_url="https://github.com/m0lte/dapps/releases/download/${dapps_version}/dapps-${rid}"
dapps_cache_ok() {
[ -f "$dapps_cache" ] && echo "${dapps_sha256} ${dapps_cache}" | sha256sum --check --status -
dapps_manifest_cache="$root/artifacts/cache/dapps-${dapps_version}-pdn-app.yaml"
# dapps_pin_ok <file> <sha256> — the file exists and matches its pin.
dapps_pin_ok() {
[ -f "$1" ] && echo "$2 $1" | sha256sum --check --status -
}
if ! dapps_cache_ok; then
echo "==> fetch DAPPS ${dapps_version} (${rid}) from the published release"
mkdir -p "$(dirname "$dapps_cache")"
if curl -fSL --retry 3 -o "${dapps_cache}.tmp" "$dapps_url"; then
mv "${dapps_cache}.tmp" "$dapps_cache"
if ! dapps_cache_ok; then
echo "ERROR: $dapps_url does not match the pinned sha256 (${dapps_sha256})." >&2
echo " Refusing to package an unverified binary. If the dapps release was" >&2
echo " re-cut, re-pin dapps_version + all three hashes together." >&2
# dapps_fetch <asset> <cache> <sha256> — cached, pin-verified fetch of one release
# asset. Returns 0 with a verified file at <cache>; returns 1 only when the release
# is unreachable and no valid cache exists; a FRESH download failing its pin exits.
dapps_fetch() {
local asset="$1" cache="$2" sha="$3"
local url="https://github.com/m0lte/dapps/releases/download/${dapps_version}/${asset}"
if dapps_pin_ok "$cache" "$sha"; then return 0; fi
echo "==> fetch DAPPS ${dapps_version} asset ${asset} from the published release"
mkdir -p "$(dirname "$cache")"
if curl -fSL --retry 3 -o "${cache}.tmp" "$url"; then
mv "${cache}.tmp" "$cache"
if ! dapps_pin_ok "$cache" "$sha"; then
echo "ERROR: $url does not match the pinned sha256 (${sha})." >&2
echo " Refusing to package an unverified artifact. If the dapps release was" >&2
echo " re-cut, re-pin dapps_version + all four hashes together." >&2
exit 1
fi
else
rm -f "${dapps_cache}.tmp"
return 0
fi
fi
if dapps_cache_ok; then
rm -f "${cache}.tmp"
return 1
}
if dapps_fetch "dapps-${rid}" "$dapps_cache" "$dapps_sha256" &&
dapps_fetch "pdn-app.yaml" "$dapps_manifest_cache" "$dapps_manifest_sha256"; then
install -d "$stage/usr/share/packetnet/apps/dapps"
install -m 0644 "$root/packaging/dapps/pdn-app.yaml" "$stage/usr/share/packetnet/apps/dapps/pdn-app.yaml"
install -m 0644 "$dapps_manifest_cache" "$stage/usr/share/packetnet/apps/dapps/pdn-app.yaml"
install -m 0755 "$dapps_cache" "$stage/usr/share/packetnet/apps/dapps/dapps"
else
echo "WARNING: could not fetch DAPPS ${dapps_version} (${rid}) and no valid cached" >&2
echo " copy exists — building the deb WITHOUT the bundled dapps package." >&2
echo "WARNING: could not fetch DAPPS ${dapps_version} (${rid} binary + manifest) and no" >&2
echo " valid cached copy exists — building the deb WITHOUT the bundled dapps package." >&2
fi
sed -e "s/@ARCH@/$arch/" -e "s/@VERSION@/$version/" \
"$root/packaging/control.in" > "$stage/DEBIAN/control"
Expand Down
Loading
Loading