Files
n_os_tr/plans/slice_bc_fips_crelay.md
Laan Tungir 6e2164abe5 [WARNING] No existing semantic tags found. Starting from v0.0.0
v0.0.1 - Reorganize ISO build tree, add docs/plans/scripts, and stage Phase 2 Slice B+C service integration artifacts
2026-04-29 13:09:28 -04:00

28 KiB

Slice B + C: Add fips and c-relay to the n-OS-tr ISO

Status: Ready for implementation

This document specifies the work required to enable the fips mesh-routing daemon and the c-relay Nostr relay on the live ISO built by build.sh, replacing the current Slice A (ginxsom + nginx only) with the full three-service stack planned in iso_architecture.md.


1. Design Decisions (captured from user)

# Topic Decision
1 Source of c-relay binary User-provided, already downloaded into includes/c-relay/
2 Source of fips binaries Build locally via cargo deb during build.sh
3 c-relay admin nsec strategy Ephemeral — c-relay self-provisions per boot, admin nsec captured from journald
4 fips identity Ephemeral — new npub per boot, no persistent key management for this slice
5 fips peer config Connect to the same public bootstrap node used elsewhere in the repo: npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98 at 217.77.8.91:2121 (UDP), per examples/sidecar-nostr-relay/.env et al.
6 fips transport Ethernet enabled, plus UDP for the static peer
7 fips-gateway Disabled (default)
8 c-relay exposure nginx reverse-proxies wss://host/relayws://127.0.0.1:8888/; nginx reverse-proxies /admin/http://127.0.0.1:8888/api/
9 Scope Full Slice B+C — services, nginx wiring, package deps, smoke test, MOTD, README updates
10 Key management / identity continuity Out of scope for this slice — revisit in a later pass

2. What Already Exists (Slice A baseline)

Confirmed present and working, per source inspection:

Slice A smoke test passes 5 PASS, 0 FAIL, 8 SKIP on a freshly-booted USB.


3. What Needs to Change (target state)

flowchart LR
    subgraph Build [Build-time build.sh]
        BS[build.sh]
        CDB[cargo deb in<br/>includes/fips]
        FDeb[iso/local-artifacts/fips_0.3.0_amd64.deb]
        CRX[includes/c-relay/c_relay_x86]
        CRC[iso/local-artifacts/c_relay_x86]
        BS --> CDB --> FDeb
        BS --> CRC
    end
    subgraph Chroot [live-build chroot phase]
        H1[0010-fetch-artifacts.hook.chroot]
        FDeb --> H1
        CRC --> H1
        H1 -->|dpkg -i| FInst[/usr/bin/fips etc]
        H1 -->|install -m 0755| CInst[/opt/c-relay/c_relay_x86]
        H1 -->|adduser --system| CUsr[c-relay system user]
        H1 -->|write fips.yaml| FCfg[/etc/fips/fips.yaml]
    end
    subgraph Boot [Runtime at boot]
        Fb[n-os-tr-firstboot]
        Fips[fips.service]
        FDns[fips-dns.service]
        CRel[c-relay.service]
        Gx[ginxsom.service]
        Ng[nginx.service]
        Fb --> Gx
        Fips --> FDns
        Ng -->|wss /relay| CRel
        Ng -->|http /admin/| CRel
    end

Summary of changes

Area Change
Build system build.sh gains a pre-build step: build fips .deb via cargo deb and stage artifacts into iso/local-artifacts/
Artifact layout New directory iso/local-artifacts/ holds fips_*_amd64.deb and c_relay_x86 — gitignored
Chroot hook (new) iso/config/hooks/live/0010-fetch-artifacts.hook.chroot installs those two artifacts into the chroot
Package list iso/config/package-lists/base.list.chroot adds runtime deps: libdbus-1-3, iproute2, nftables (optional for gateway mode later)
fips config New iso/config/includes.chroot/etc/fips/fips.yaml overriding the package default with ethernet + static UDP peer enabled
c-relay service New iso/config/includes.chroot/etc/systemd/system/c-relay.service — adapted from upstream unit
c-relay user Chroot hook creates c-relay system user + /opt/c-relay/ working dir
nginx config iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf gains /relay wss upgrade and /admin/ proxy locations
Service-enable hook 0020-enable-services.hook.chroot also enables fips.service, fips-dns.service, c-relay.service
Smoke test n-os-tr-smoketest replaces the 8 SKIPs with real checks
MOTD / README First-boot script and docs updated to surface how to find c-relay admin nsec and fips identity
.gitignore Add iso/local-artifacts/

4. Concrete Artifact Details

4.1 c-relay static binary

  • Source: includes/c_relay_static_x86_64 — user-downloaded static-musl build, already present at the top level of includes/ (NOT inside includes/c-relay/). Filename confirmed by directory listing.
  • Staged as: iso/config/includes.chroot_before_packages/live-artifacts/c_relay_x86 (canonical name used by the chroot hook and systemd unit — we rename on copy so c-relay.service can reference a stable filename regardless of which upstream build variant the user drops in).
  • Target in chroot: /opt/c-relay/c_relay_x86, mode 0755, owner c-relay:c-relay.
  • Copied by: build.sh copies includes/c_relay_static_x86_64 → staging area → chroot hook installs to /opt/c-relay/.

4.2 iso/local-artifacts/fips_0.3.0_amd64.deb

  • Source: built by build.sh via cd includes/fips && packaging/debian/build-deb.sh. Requires cargo-deb installed on the build host (cargo install cargo-deb if absent; build.sh will check and fail clearly).
  • Contents (per Cargo.toml):
    • /usr/bin/fips, /usr/bin/fipsctl, /usr/bin/fipstop, /usr/bin/fips-gateway
    • /etc/fips/fips.yaml (package default — will be overridden by our includes.chroot version)
    • /etc/fips/hosts
    • /lib/systemd/system/fips.service, /lib/systemd/system/fips-dns.service, /lib/systemd/system/fips-gateway.service
    • /usr/lib/fips/fips-dns-setup, /usr/lib/fips/fips-dns-teardown
    • /usr/lib/tmpfiles.d/fips.conf
  • Runtime deps (per Cargo.toml): libc6, systemd, libdbus-1-3, recommends bluez (skipped — not needed for non-BLE).
  • Installed by: chroot hook runs dpkg -i /tmp/artifacts/fips_*_amd64.deb then cleans up. The postinst enables fips.service and fips-dns.service automatically.

4.3 iso/config/includes.chroot/etc/fips/fips.yaml

Overrides the Debian-packaged default at /etc/fips/fips.yaml. The live-build includes.chroot mechanism copies this on top after package install. Content:

# n-OS-tr fips configuration.
# Ephemeral identity: new keypair every boot (default).
# To make identity persistent across reboots on a live USB with a
# persistence partition, set node.identity.persistent: true.

node:
  identity:
    # ephemeral by default

tun:
  enabled: true
  name: fips0
  mtu: 1280

dns:
  enabled: true
  port: 5354

transports:
  udp:
    bind_addr: "0.0.0.0:2121"
  tcp:
    bind_addr: "0.0.0.0:8443"
  ethernet:
    # Ethernet transport auto-discovers LAN peers.
    # interface: omitted → fips picks the first non-loopback interface.
    # Override with an explicit interface name if your board uses
    # something other than the default (e.g. enp5s0, eno1, eth0).
    discovery: true
    announce: true
    auto_connect: true
    accept_connections: true

# Static peer for internet bootstrap.
# Matches the same "fips-test-node" / "vps-chi" public node used across
# the repo's example configs (see includes/fips/examples/... and
# includes/fips/testing/sidecar/.env).
peers:
  - npub: "npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98"
    alias: "fips-test-node"
    addresses:
      - transport: udp
        addr: "217.77.8.91:2121"
    connect_policy: auto_connect

Notes:

  • Omitting ethernet.interface relies on fips's auto-selection logic. If that doesn't pick a sensible interface, add interface: "eth0" (verified post-boot via ip link show).
  • Keeping the udp bootstrap peer in addition to ethernet gives the mesh internet reachability even when the LAN has no other fips peers.

4.4 iso/config/includes.chroot/etc/systemd/system/c-relay.service

Adapted from upstream with minor tweaks for the live environment:

[Unit]
Description=C Nostr Relay (n-OS-tr slice C)
Documentation=file:///usr/share/doc/n-os-tr/README
After=network.target n-os-tr-firstboot.service
Wants=network-online.target

[Service]
Type=simple
User=c-relay
Group=c-relay
WorkingDirectory=/opt/c-relay
Environment=DEBUG_LEVEL=0
# c-relay self-provisions admin + relay keys on first start and prints
# the admin nsec to stdout (captured by journald).
ExecStart=/opt/c-relay/c_relay_x86 --debug-level=${DEBUG_LEVEL}
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=c-relay

# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/c-relay
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6
LimitNOFILE=65536
LimitNPROC=4096

[Install]
WantedBy=multi-user.target

4.5 Updated nginx site — /relay wss + /admin/ proxy

New locations appended to iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf inside the existing server { listen 443 ssl; ... } block, before the ginxsom FastCGI blocks:

    # --- c-relay reverse proxy (slice C) ---------------------------------

    # Nostr relay WebSocket: wss://host/relay → ws://127.0.0.1:8888/
    # The client library expects a WebSocket upgrade on /relay; c-relay
    # itself listens on "/" so we rewrite and proxy to its root.
    location = /relay {
        proxy_pass http://127.0.0.1:8888/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
        proxy_send_timeout 86400;
    }

    # NIP-11 relay info doc (available at wss://host/relay with
    # Accept: application/nostr+json). Proxied to the same backend.
    # If you want /relay (GET without upgrade) to return NIP-11 too,
    # the location above already handles it — c-relay's NIP-11 handler
    # triggers based on the Accept header, not the path.

    # c-relay embedded web admin UI: https://host/admin/ → http://127.0.0.1:8888/api/
    location /admin/ {
        proxy_pass http://127.0.0.1:8888/api/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

Notes:

  • The /admin/ path deliberately overlaps with a Blossom admin path, but Blossom's admin routes go via the FastCGI @ginxsom named location and c-relay's admin is explicitly reverse-proxied — nginx's longest-prefix match means /admin/ → c-relay wins for GET/POST, and ginxsom admin is reached via a different path (if ginxsom has one). Potential conflict with Slice A — need to confirm ginxsom doesn't rely on /admin/. Current n-os-tr.conf:53 has location /admin/ { try_files $uri @ginxsom; } — this will need to be removed or renamed (e.g. /blossom-admin/) to avoid collision. See §6 Open Questions.
  • The landing page at / (static /var/www/html/index.html) is unaffected.

4.6 New chroot hook — 0010-fetch-artifacts.hook.chroot

#!/bin/sh
# Install c-relay and fips into the chroot from iso/local-artifacts/.
set -e

ART=/live-artifacts

if [ ! -d "$ART" ]; then
    echo "[fetch-artifacts] no $ART; skipping" >&2
    exit 0
fi

# --- c-relay -----------------------------------------------------------
if [ -f "$ART/c_relay_x86" ]; then
    echo "[fetch-artifacts] installing c-relay binary"
    # Create system user and directory
    if ! getent passwd c-relay >/dev/null 2>&1; then
        adduser --system --no-create-home --group --home /opt/c-relay c-relay
    fi
    mkdir -p /opt/c-relay
    install -m 0755 -o c-relay -g c-relay \
        "$ART/c_relay_x86" /opt/c-relay/c_relay_x86
    chown -R c-relay:c-relay /opt/c-relay
else
    echo "[fetch-artifacts] WARNING: $ART/c_relay_x86 not found" >&2
fi

# --- fips --------------------------------------------------------------
FIPS_DEB=$(ls "$ART"/fips_*_amd64.deb 2>/dev/null | head -1 || true)
if [ -n "$FIPS_DEB" ] && [ -f "$FIPS_DEB" ]; then
    echo "[fetch-artifacts] installing fips from $FIPS_DEB"
    dpkg -i "$FIPS_DEB" || apt-get -f install -y
else
    echo "[fetch-artifacts] WARNING: no fips_*_amd64.deb in $ART" >&2
fi

How $ART gets populated in the chroot: live-build copies iso/local-artifacts/ into /live-artifacts/ inside the chroot via an includes.chroot_before_packages/ entry that bind-mounts or symlinks the directory, OR more simply, we place the artifacts directly under iso/config/includes.chroot_before_packages/live-artifacts/ so live-build copies them before package install. See §5 step 2 for the exact location.

4.7 Updated build.sh

Inserted before the sudo "$REPO_ROOT/lb-wrapper.sh" config line:

# --- Stage Slice B artifacts ------------------------------------------------
ARTIFACTS="$WORKSPACE_ISO_DIR/config/includes.chroot_before_packages/live-artifacts"
mkdir -p "$ARTIFACTS"

# 1. c-relay: copy the user-provided binary from includes/c-relay/
CRELAY_SRC=""
for candidate in \
    "$REPO_ROOT/includes/c-relay/c_relay_x86" \
    "$REPO_ROOT/includes/c-relay/build/c_relay_x86" \
    "$REPO_ROOT/includes/c-relay/c-relay" ; do
    if [[ -x "$candidate" ]]; then CRELAY_SRC="$candidate"; break; fi
done
if [[ -z "$CRELAY_SRC" ]]; then
    echo "[build.sh] ERROR: no c-relay binary found. Looked for:" >&2
    echo "  includes/c-relay/c_relay_x86" >&2
    echo "  includes/c-relay/build/c_relay_x86" >&2
    echo "  includes/c-relay/c-relay" >&2
    exit 1
fi
cp "$CRELAY_SRC" "$ARTIFACTS/c_relay_x86"
chmod 0755 "$ARTIFACTS/c_relay_x86"
echo "[build.sh] staged c-relay from $CRELAY_SRC"

# 2. fips: build the .deb (requires cargo-deb)
if ! command -v cargo-deb >/dev/null 2>&1; then
    echo "[build.sh] ERROR: cargo-deb not installed. Run: cargo install cargo-deb" >&2
    exit 1
fi
pushd "$REPO_ROOT/includes/fips" >/dev/null
packaging/debian/build-deb.sh
popd >/dev/null
FIPS_DEB=$(ls "$REPO_ROOT/includes/fips/deploy"/fips_*_amd64.deb | sort | tail -1)
if [[ -z "$FIPS_DEB" || ! -f "$FIPS_DEB" ]]; then
    echo "[build.sh] ERROR: fips .deb build produced no artifact" >&2
    exit 1
fi
cp "$FIPS_DEB" "$ARTIFACTS/"
echo "[build.sh] staged fips .deb: $(basename "$FIPS_DEB")"

4.8 Updated package list — base.list.chroot

Add runtime deps needed by fips (already pulled in transitively by the .deb but explicit is safer) and by the smoke test:

nginx-light
spawn-fcgi
libfcgi-bin
ca-certificates
openssl
curl
jq
vim
htop
# Slice B/C additions:
libdbus-1-3
iproute2
nftables

4.9 Updated 0020-enable-services.hook.chroot

#!/bin/sh
set -e

# Nginx
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/n-os-tr.conf /etc/nginx/sites-enabled/n-os-tr.conf
systemctl enable nginx.service

# Slice A
systemctl enable ginxsom.service
systemctl enable n-os-tr-firstboot.service

# Slice B (fips) — units installed by the .deb postinst already enable
# them, but we're explicit for idempotence:
systemctl enable fips.service || true
systemctl enable fips-dns.service || true

# Slice C (c-relay)
systemctl enable c-relay.service

4.10 Updated smoke test

Replace the fips and c-relay SKIP blocks in n-os-tr-smoketest with real checks:

# -------------------- fips mesh daemon -----------------------------
section "fips mesh daemon"

check "fips.service active" systemctl is-active fips.service
check "fips-dns.service active" systemctl is-active fips-dns.service
check "fips0 interface present" ip link show fips0

# fipsctl identity should return an npub-shaped string
npub=$(fipsctl identity 2>/dev/null | head -1 | tr -d '[:space:]')
case "$npub" in
    npub1*) pass "fipsctl identity returns npub" "${npub:0:20}..." ;;
    *)      fail "fipsctl identity returns npub" "got: ${npub:-<empty>}" ;;
esac

# fips UDP transport should be listening
check "fips UDP bound on :2121" bash -c 'ss -ulnp 2>/dev/null | grep -q ":2121"'

# -------------------- c-relay nostr relay --------------------------
section "c-relay nostr relay"

check "c-relay.service active" systemctl is-active c-relay.service
check "c-relay listening on :8888" bash -c 'ss -tlnp 2>/dev/null | grep -q ":8888"'

# The admin nsec should have been logged during first startup
if journalctl -u c-relay.service --no-pager 2>/dev/null | \
    grep -q "Admin Private Key:"; then
    pass "admin nsec logged in journal" "found"
else
    fail "admin nsec logged in journal" "grep miss"
fi

# wss end-to-end via nginx, using the shipped nak:
if timeout 10 nak req --relay wss://localhost/relay -k 1 -l 1 \
    >/dev/null 2>&1; then
    pass "wss://localhost/relay answers REQ" "ok"
else
    fail "wss://localhost/relay answers REQ" "timeout or error"
fi

# NIP-11 relay info doc
nip11=$(curl -sk -H 'Accept: application/nostr+json' \
    https://localhost/relay 2>/dev/null)
if echo "$nip11" | jq -e '.name' >/dev/null 2>&1; then
    pass "NIP-11 info doc reachable" "name=$(echo "$nip11" | jq -r .name)"
else
    fail "NIP-11 info doc reachable" "no JSON .name"
fi

# c-relay embedded admin UI via nginx
status=$(curl -sk -o /dev/null -w '%{http_code}' https://localhost/admin/ 2>/dev/null)
case "$status" in
    200|302|401) pass "admin UI reachable via nginx" "HTTP $status" ;;
    *)           fail "admin UI reachable via nginx" "HTTP $status" ;;
esac

Target final summary: ~15 PASS / 0 FAIL / 0 SKIP.

4.11 MOTD and README updates

The n-os-tr-firstboot script's MOTD block gains additional hints:

  n-OS-tr — Nostr-addressed mesh node (preview)

  Ginxsom (Blossom) server pubkey (hex):
      $GINXSOM_SERVER_PUBKEY
      retrieve nsec: cat /var/lib/n-os-tr/keys/ginxsom.nsec

  c-relay Nostr relay:
      wss://$(hostname)/relay         (admin nsec: journalctl -u c-relay | grep 'Admin Private Key')
      https://$(hostname)/admin/      (web admin UI)

  fips mesh daemon:
      fipsctl identity                (show npub)
      fipsctl peers                   (list peers)

  Quick health check:      n-os-tr-smoketest

The iso/config/includes.chroot/usr/share/doc/n-os-tr/README gets corresponding additions.


5. Build & Deploy Sequence

  1. Place c-relay binary at includes/c-relay/c_relay_x86 (or one of the fallback paths build.sh checks). Ensure it's chmod +x and runs standalone.
  2. Install cargo-deb on the build host: cargo install cargo-deb.
  3. Edit all files listed in §3 according to §4.
  4. Move artifacts staging location:
    • New directory: iso/config/includes.chroot_before_packages/live-artifacts/ — gitignored.
    • build.sh writes c-relay binary and fips .deb here.
    • 0010-fetch-artifacts.hook.chroot reads from /live-artifacts/ inside the chroot (live-build copies the includes.chroot_before_packages tree into the chroot root before packages install).
  5. Add iso/config/includes.chroot_before_packages/live-artifacts/ to .gitignore.
  6. Full clean build: sudo ./build.sh --clean (needed because package list changed).
  7. Burn the resulting iso/live-image-amd64.hybrid.iso to USB with dd.
  8. Boot on the B650I machine.
  9. Verify: run n-os-tr-smoketest — expect all checks to PASS.

6. Open Questions / Known Conflicts

6.1 nginx /admin/ path collision

Slice A's n-os-tr.conf:53 routes /admin/ to ginxsom. Slice C wants /admin/ for c-relay. Resolution proposed: change Slice A's Blossom admin to /blossom/ (if ginxsom supports path rewriting) or /blossom-admin/. Need to check ginxsom's source to see whether its admin endpoints are hardcoded to /admin/ or whether the FastCGI layer can remap them.

6.2 Fips ethernet auto-interface selection

If the B650I's Ethernet shows up as enp5s0 or similar and fips's "auto-pick first non-loopback" heuristic grabs the wrong interface (e.g. Wi-Fi — though we explicitly said runtime Wi-Fi is fine, we don't want fips scanning it), we may need to hardcode ethernet.interface: "enp5s0" in fips.yaml. Resolution: check ip link show on first boot; update if needed.

6.3 Stray file =4 in includes/c-relay/

Shown in the directory listing but not the c-relay binary (the real binary is includes/c_relay_static_x86_64 at the top level of includes/). Likely a shell-redirect typo artifact (command >=4 file or similar). Safe to delete during cleanup; does not affect the build.

6.4 c-relay writable database location

c-relay writes .nrdb files to its WorkingDirectory (/opt/c-relay/). In a live session with ephemeral rootfs this works — the writes go to the tmpfs union layer. For persistence-partition boots we'd want /opt/c-relay/ on the persistence mount. Not addressed in this slice per decision #10.

6.5 fips running as root

The fips Debian package runs fips as root (needs TUN + raw sockets). The hardening in fips.service is meaningful but fips itself is privileged. Acceptable for this slice.

6.6 Reverse proxy's X-Forwarded-Proto and c-relay's NIP-42

NIP-42 requires the relay to know its own URL (for the ["relay", "url"] tag in the AUTH challenge). c-relay has logic that falls back to ws://127.0.0.1:PORT — this means NIP-42 challenges will reference the internal address, not wss://host/relay. Clients may then fail auth. Mitigation: c-relay has a configurable relay_url config key (set via admin event). Post-boot procedure documented in updated README for users who want NIP-42 to work correctly. Not blocking for basic operation — the relay accepts unauthenticated connections by default.


7. Success Criteria

From a booted USB on fresh hardware with wired Ethernet:

  • systemctl status fips-dns ginxsom c-relay nginx n-os-tr-firstboot — all active
  • fipsctl identity — prints a valid npub
  • fipsctl peers — at minimum lists fips-test-node (may show as "connecting" if UDP blocked)
  • ip link show fips0 — fips0 TUN interface up
  • journalctl -u c-relay | grep 'Admin Private Key' — returns the nsec (once)
  • curl -k https://localhost/ — landing page
  • curl -k -I https://localhost/admin/ — returns 200 or 302 (c-relay UI)
  • nak req --relay wss://localhost/relay -k 1 -l 1 — returns ["EOSE",...] after an empty result
  • curl -ksI https://localhost/0000000000000000000000000000000000000000000000000000000000000000 — 404 (ginxsom still works)
  • n-os-tr-smoketest15 PASS / 0 FAIL / 0 SKIP

8. Rollback

If something goes sideways during development:

  • The entire Slice A → Slice B+C diff is confined to these files/directories:
    build.sh                                                      (additive step)
    iso/config/hooks/live/0010-fetch-artifacts.hook.chroot        (new)
    iso/config/hooks/live/0020-enable-services.hook.chroot        (edited)
    iso/config/package-lists/base.list.chroot                     (edited)
    iso/config/includes.chroot/etc/fips/                          (new dir)
    iso/config/includes.chroot/etc/systemd/system/c-relay.service (new)
    iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf (edited)
    iso/config/includes.chroot/usr/local/sbin/n-os-tr-firstboot   (edited motd)
    iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest    (edited)
    iso/config/includes.chroot/usr/share/doc/n-os-tr/README       (edited)
    iso/config/includes.chroot_before_packages/                   (new, gitignored)
    .gitignore                                                    (edited)
    
  • A revert is a git checkout of those paths plus removal of iso/config/includes.chroot_before_packages/.

9. Out of Scope (deferred to later slices)

  • Persistent identity (ginxsom nsec, c-relay admin nsec, fips npub survive reboots).
  • Gitea release fetch for artifacts (current plan is local-only).
  • c-relay relay_url auto-configuration for NIP-42 (manual admin event for now).
  • /admin/ conflict resolution if ginxsom truly hardcodes that path.
  • fips-gateway service (disabled; users can enable manually for LAN translation).
  • Tor transport for fips (transport is available but not wired into the config).
  • Installer variant (live-only for now).
  • arm64 build.
  • Signed / reproducible builds.
  • Hardening tests: SELinux, AppArmor profiles.

10. References