Skip to content

Orion-X Phoenix Edition v3.0.0

Choose a tag to compare

@jarocki jarocki released this 19 Oct 03:32
· 129 commits to main since this release

What this release is. The v2.2.0 release-candidate line (rc5–rc9, below), taken
through a full quality pass and shipped as Orion-X Phoenix Edition 3.0.0: eight
independent reviews of the rc9 image (operator experience, Python, shell, systemd and
AppArmor, packages and build, documentation, security, release engineering — 253
findings), five fix groups working in parallel worktrees, and a second round of
defects found by booting and recording the image for the release video. Nothing
below was accepted without a test that failed before the fix and passes after it.

ISO identity. SHA-256 c952ca5be03789208e39ef1807c1f09c1c15fb1f82c223272c8c3c2007332386,
3,131,211,776 bytes (3.13 GB), built 2026-10-08 16:25–16:58 MDT from 2da37512 with a
clean chroot (only the bootstrap stage reused). Baked ISO_VERSION=v3.0.0, baked README ==
repo. Gates on this image: hooks-applied 19/0; content-presence in release mode
(ORIONX_RELEASE_GATE=1 ORIONX_EXPECT_VERSION=v3.0.0, shellcheck and lsinitramfs present)
391/0/0; QEMU BIOS 104 s / UEFI 112 s. Booted on the reference laptop (Lenovo) by the
owner on 2026-10-18: works as advertised (DEC-PHASE13-001 satisfied). The
CHANGELOG, README and User Guide copies baked into the image predate this identity line,
as every release's must.

Added

  • Boot menu entry "Orion-X Live (no questions)" — appends orionx.wizard=0; the
    first-boot wizard takes every default. Prompts now time out after 30 s (an
    unattended boot waits about 2 minutes, not 6) (DEC-PHASE12-106).
  • A real training capture. ~/Analysis/pcaps/apt_malware_traffic.pcap was a
    42-byte text placeholder that tshark read as an empty capture; it is now a
    deterministic synthetic intrusion (DNS + HTTP stager, jittered TLS beacons with
    SNI, DNS TXT tunnelling, an internal SYN sweep, SMB2 negotiate) over RFC 1918 /
    RFC 5737 addresses and .example names, generated by
    tools/samples/make_training_pcap.py (DEC-PHASE12-141).
  • Team pre-shared key for the mesh, optional and exchanged out of band:
    orionx-mesh psk generate|install|remove|status. Two stock decks peer without it.
  • Release tooling. scripts/release/stage-split-release.sh publishes the >2 GB
    ISO as signed 190 MiB parts with SHA256SUMS/SHA512SUMS and reassembly
    instructions; scripts/release/ci-local.sh runs the CI gates locally; lint, e2e
    and QEMU workflows run on release/** branches (DEC-PHASE12-115, -123).
  • Two release videos — the guided walkthrough (docs/media/orionx-guided-demo-v3.0.0.*)
    and the trailer (docs/media/orionx-trailer-v3.0.0.*), each as mp4 + vtt + transcript +
    poster, 720p in the repo, 1080p masters on the release — and their one pipeline
    (tools/guided-demo/cinematic/): boot footage
    captured from the real ISO in QEMU, UI scenes recorded from the ISO's own root
    filesystem, the deck's own R.A.I.N. cues and voice, a synthesised score and an
    offline neural narrator; captions and transcript derive from one script
    (DEC-PHASE12-062 … -064, -140).
  • New test suites: test_cockpit_gtk (the Cockpit under a real GTK main loop on
    Xvfb), test_firewall_behaviour (real packets through network namespaces),
    test_unit_sandbox (systemd-analyze verify + a real dumpcap run),
    test_apparmor_load, test_firefox_policies, test_bus_reader,
    test_operator_surfaces, test_release_promises, test_release_tooling,
    test_makefile_gates, test_hooks_applied_gate, test_sample_pcaps,
    test_artifact_analyzer_cli, test_cockpit_honesty.

Fixed — Cockpit

  • orionx-cockpit --tab X always opened LIVE, including from the menu entry
    and orionx-control-center: GtkNotebook ignores a page selection made before
    show_all(). Found while recording the release video.
  • Choosing a threat-posture tier says "requested" until orionx-postured
    confirms enforcement
    , or says NOT enforced with the remedy. A failed write
    reverts the control and shows the error. Every state change toasts whether it
    survives reboot (DEC-PHASE12-065…074).
  • The Comms tab derives the client URL from the listener Synapse actually binds
    (/etc/matrix-synapse/conf.d/orionx.yaml, then homeserver.yaml); it used to
    print https://<ip>:8008, which matched nothing.
  • "Download Samples" and "Storyboard Generator" guided actions pass arguments the
    scripts accept (both could never run). Orion Tools lists catalogue entries
    installed as Debian packages (nmap, tshark, yara … were hidden).
  • DEFENSIVE ACTIONS reads orionx-heald's published /run/orionx/healing-status.json
    (root-only chain is no longer read, and the panel no longer shows nothing when
    actions are in force). A missing or stale snapshot says so.
  • The panel mesh widget, Mesh tab, Awareness and the LIVE LED read the root-written
    mesh snapshot; nothing in the GUI runs sudo. "stale (N s)" past 30 s.
  • Probes run in worker threads and only for the visible tab; a slow systemctl,
    nmcli or matrix-commander no longer freezes the window (was up to 27 s).
  • The LIVE tab fits 1366×768 and opens maximised; text is measured and ellipsised;
    the drill-down wraps and pages; severity is a word as well as a colour; no text
    under 11 px; one toast system with a log at ~/.cache/orionx/cockpit.log.
    Ctrl+Q quits; a stray q/Esc no longer closes the live view; Alt+1…8 switch tabs.
  • Squelch/tune results keep orionx-tune's lines with "survives reboot" first;
    nothing is cut at 160 characters.
  • "Test alert" reports orionx-rain's real exit status; orionx-rain --test exits
    1 when no cue played.
  • Event-bus readers (Cockpit and R.A.I.N.) no longer lose a line read mid-write or
    events written just after a rotation; R.A.I.N. survives the bus file being
    deleted (it crashed and stayed dead for the session).
  • Retired names are gone from every operator-facing string: "Control Center",
    "IR Tools", "Investigation Surface". orionx-control-center --version reports
    the image's version.

Fixed — daemons and detection

  • One malformed entry in tuning.json silenced every IDS alert (the error was
    swallowed); rules are validated on load, bad ones reported once on the bus.
  • Operator-writable tuning text reached root's Suricata threshold file unescaped
    (a newline injected suppress gen_id 0, sig_id 0); fields are validated and
    single-line before root writes them.
  • Root daemons read tuning and posture files only from the operator's home, never
    through a symlink or a file another user can write (they chose "newest across
    every /home/*").
  • The healing engine acts only on bus events signed by root producers (HMAC, key in
    a root-only file); anything else can at most become a labelled suggestion.
  • The event-bus speech validator no longer rejects sentences with words ending in
    "s"; R.A.I.N. remedies name the shipped nebula CLI (they said orionx-nebula,
    which does not exist).
  • On-demand PCAP capture works: the orionx-capture@ sandbox killed dumpcap with
    SIGSYS, and ReadWritePaths=/var/lib/orionx named a directory the image did not
    have (postured failed with 226/NAMESPACE).
  • LAN mesh discovery never added a peer (the listener read the sender address from a
    variable that was never set and then died). Beacons are validated (single host in
    the mesh subnet, never rewriting an existing peer), rate-limited, rejects logged.
    join starts the discovery/beacon/health/status units and leave stops them
    (they stayed dead after a leave). mesh_genkeys fails loudly on a write error.
  • setup-matrix.sh --mode server died at the registration-secret line (SIGPIPE
    under pipefail). It now writes one listener (http, 8008, bound to 127.0.0.1 and
    the wg0 address), keeps registration closed, passes the admin password through a
    file, checks for root and a route first, and pins the matrix.org and Element apt
    keys by fingerprint. One Synapse unit: the package's matrix-synapse.service
    with an Orion-X drop-in; matrix-synapse-orionx.service (never installed) is gone.
  • artifact-analyzer.py wrote ./analysis_results wherever the terminal was and
    died with a raw traceback from an unwritable directory; it now writes under
    ~/Analysis/results/ and reports an unwritable -o in a sentence.
  • The Workbench rejects requests not addressed to 127.0.0.1/localhost (DNS-rebinding
    defence), sends nosniff, no longer builds its full status for every static file,
    runs one server per operator (--status, --stop), and opens in its own tmpfs
    Firefox profile, never the OSINT browsing profile (DEC-PHASE12-142).

Fixed — security posture (default image)

  • Firewall: 22, 8008, 8448 and 55555 were open on every interface. Now: on
    LAN interfaces only established/related, DHCP, WireGuard 51820/udp and the
    rate-limited mesh beacon; SSH and Matrix only on wg0; restarting the firewall
    reloads only its own table (it used to flush Auto-Healing's blocks)
    (DEC-PHASE12-104).
  • sshd is installed but not started at boot. The first-boot wizard's "SSH admin
    one-shot" (a root private key and its passphrase, written world-readable to the
    pre-login banner, for a login sshd refuses) is removed (#98). Key-only login for
    orionx-operator over wg0 when the operator starts sshd.
  • ollama's "no outbound network" is enforced by the kernel (IPAddressDeny=any +
    IPAddressAllow=localhost on the unit); the AppArmor profile could not express it
    and also lacked exec permission for ollama's own runner. The dead Synapse AppArmor
    profile (attached to a symlink) is removed; the AppArmor loader reports failed
    profiles by name and the Nebula runtime refuses to start unconfined.
  • The wizard no longer creates mesh keys at all (orionx-mesh join makes them,
    0600, on first use), no longer renames the account into a state without
    sudo/polkit, and no longer says the
    account is "passwordless" (the password is live). Wi-Fi PSKs go to a 0600
    keyfile, not nmcli's argv.
  • The deck sends no DHCP hostname, no mesh beacon before a join, runs no apt timers,
    and exim4 no longer runs. Firefox ships an enterprise policy (telemetry, studies,
    DoH and WebRTC address leaks off). Root unit log files under /var/log/orionx
    can no longer be squatted (the directory stays 1777 for operator tools, DEC-PHASE12-108).
  • Build-time supply chain: every pip install is pinned with sha256 hashes
    (/usr/share/orionx/pip/), volatility3 lives in its own venv (vol kept on PATH),
    nuclei-templates is pinned to a commit, the Zeek apt key is fingerprint-pinned and
    scoped with signed-by, every optional installer verifies a SHA-256, CesiumJS's
    shared default token is removed and its licence ships.

Fixed — build, release and gates

  • make test-unit hid Python failures (2>/dev/null || echo "No Python unit tests found yet"; 12 were failing) and stopped at the first failing bash suite. It now
    runs everything and lists every failure (#11). The 11 stale pytest tests assert
    real state.
  • The macOS build wrapper copied every ISO in the build volume back to the host,
    including stale ones; it publishes only this build's ISO, only on success.
    build-iso.sh refuses a release-looking tag without a CHANGELOG section and
    fails on stale-stage reuse; extract-release-notes.sh fails loudly.
  • The content-presence gate asserts every tool the README promises and every
    rc5–rc9 deck fix in the squashfs, and nine checks that recorded PASS on missing
    evidence now FAIL; sections 29–33 read the image, not the source tree
    (DEC-PHASE12-119). The hooks gate derives its list from the hook directories.
  • volatility3, stix2, pyfiglet and the nucleotide table are hard-fail installs
    (soft-fail let a build ship without README-listed tools and stay green).
  • make clean keeps release ISOs unless CLEAN_ISOS=1; orphaned Qt5 purged
    (~60 MB); --allow-remove-essential limited to live-build's own step;
    0500-bootloader-serial.hook.binary retired (it never found its targets; the
    config generator is the authority); orionx-diag verifies the model blobs the
    manifest lists (check 7c always skipped).

Fixed — documentation and surfaces

  • Every current-release string says v3.0.0; the rendered User Guide takes its
    release line from /etc/orionx-version so it cannot drift again. The baked
    README and User Guide called themselves rc5.
  • The ~/Analysis README named a --output flag that does not exist
    (--samples-dir). The User Guide said nothing forwards Suricata alerts to the bus
    (postured does), named a "◈ COCKPIT" button that does not exist, said the Control
    Center starts automatically, and had a broken table-of-contents link.
  • Rename propagation finished everywhere user-visible; the Cockpit has a desktop
    icon and a panel launcher; "Orion Cockpit — Tabs" is "Orion Cockpit — Network tab"
    (what it opens); the "Orion-X Mesh" menu entry runs sudo orionx-mesh status
    instead of printing usage; MOTD and orionx-help list what ships, from one list.
  • README: Nebula "listens on 127.0.0.1 only; AppArmor-confined" (the old "no
    outbound network" claim was false); Known issues section; Hack is MIT/Expat +
    Bitstream Vera (not Apache-2.0) and DejaVu Sans Mono also ships.
  • New User Guide sections: Firewall and Remote Access, mesh keys and PSK, the real
    Synapse listener, the live account and administrator rights (sudo without a
    prompt is by design for a single-operator live deck).

Known issues and decisions deferred to the owner

Each item below now has an owner decision, recorded 2026-10-18 in
MASTER_PLAN.md § Decision Log as DEC-PHASE13-001 … 012 (taken through the
/decide configurator on this list; nothing here changes the v3.0.0 image).

  • Boot-tested in QEMU (BIOS + UEFI) and, on 2026-10-18, on the reference laptop
    (Lenovo) by the owner: boots and works as advertised. DEC-PHASE13-001 is
    satisfied
    ; the deck-only checks (Mesh tab, "Set up as server", Element's keyring
    prompt, AppArmor enforcement of ollama, the Synapse drop-in sandbox) remain to be
    exercised one by one on that hardware as 3.0.1 work begins.
  • radare2 and fonts-iosevka are not shipped (#85) — DEC-PHASE13-002: close
    #85 as won't-ship (Ghidra via install-ghidra.sh; Hack + DejaVu Sans Mono).
    Zeek has no managed capture unit (ingest only) — DEC-PHASE13-004: ship
    orionx-zeek@.service in 3.0.1, templated on the interface like
    orionx-capture@, started by the Tier-1 plan beside Suricata. The gomuks
    installer refuses (upstream's asset 404s) — DEC-PHASE13-003: remove
    install-gomuks.sh; Element is the Matrix client path. TrID pins fail closed
    when the vendor updates — DEC-PHASE13-005: keep fail-closed; add a
    --print-pin operator path.
  • NetworkManager MAC randomisation was not applied — DEC-PHASE13-006:
    cloned-mac-address=stable for Wi-Fi and Ethernet (hardware MAC never leaves
    the deck; per-network address is stable so portals and DHCP survive). exim4 is
    masked rather than purged — DEC-PHASE13-007: purge in the 0900 trim hook
    (drop the 0620 mask; handle rkhunter's default-mta Recommends). Firmware scope —
    DEC-PHASE13-008: the current Wi-Fi set plus intel-microcode and
    amd64-microcode.
  • LAN mesh discovery is unauthenticated beyond beacon validation — DEC-PHASE13-009:
    auto-peer only when a team PSK is installed; otherwise hold beacons as candidates
    the Mesh tab lists. (Gated on 001.)
  • orionx-scanwatch and the posture/healing daemons still run as uid 0 —
    DEC-PHASE13-010: a dedicated orionx system user with ambient capabilities;
    journal and nftables access verified on the deck first. (Gated on 001.)
  • install-duckdb.sh installs an unpinned duckdb into system Python and
    install-geoip.sh fetches without a checksum — DEC-PHASE13-011: pin duckdb
    (version + hash) in a venv under /opt/orionx/venvs; GeoIP records the SHA-256 of
    each monthly file and refuses a changed re-download.
  • The old guided-demo recorder (tools/guided-demo/build_demo.py, #99) drove the
    retired Control Center window — DEC-PHASE13-012 (amended): keep both videos,
    one pipeline. The guided walkthrough is now tools/guided-demo/cinematic/ walkthrough.yaml, rendered by the trailer's builder from footage of the shipped
    ISO; build_demo.py and its container mirror are removed.

Download and verify

GitHub caps release assets at 2 GiB per file, so the 3131211776-byte ISO is
published as 16 parts (part-aa … part-ap). Download ALL 16 parts,
SHA256SUMS and SHA256SUMS.asc into one directory.

1. Reassemble (Linux / macOS):

   cat orionx-phoenix-edition-v3.0.0.iso.part-* > orionx-phoenix-edition-v3.0.0.iso

   Windows (cmd, or PowerShell via cmd /c):

   copy /b orionx-phoenix-edition-v3.0.0.iso.part-aa + orionx-phoenix-edition-v3.0.0.iso.part-ab + orionx-phoenix-edition-v3.0.0.iso.part-ac + orionx-phoenix-edition-v3.0.0.iso.part-ad + orionx-phoenix-edition-v3.0.0.iso.part-ae + orionx-phoenix-edition-v3.0.0.iso.part-af + orionx-phoenix-edition-v3.0.0.iso.part-ag + orionx-phoenix-edition-v3.0.0.iso.part-ah + orionx-phoenix-edition-v3.0.0.iso.part-ai + orionx-phoenix-edition-v3.0.0.iso.part-aj + orionx-phoenix-edition-v3.0.0.iso.part-ak + orionx-phoenix-edition-v3.0.0.iso.part-al + orionx-phoenix-edition-v3.0.0.iso.part-am + orionx-phoenix-edition-v3.0.0.iso.part-an + orionx-phoenix-edition-v3.0.0.iso.part-ao + orionx-phoenix-edition-v3.0.0.iso.part-ap orionx-phoenix-edition-v3.0.0.iso

2. Verify. The reassembled ISO MUST hash to:

   c952ca5be03789208e39ef1807c1f09c1c15fb1f82c223272c8c3c2007332386

   Linux:   sha256sum -c SHA256SUMS
   macOS:   shasum -a 256 -c SHA256SUMS
   Windows: Get-FileHash orionx-phoenix-edition-v3.0.0.iso -Algorithm SHA256

   SHA256SUMS also lists each part, so a bad download can be pinpointed and
   re-fetched without pulling everything again.

   Then check the signature on the checksums (signing key
   4CB08BD1D0B3281613DD15DB1DCCDF47FEEDEEEF — compare it with the fingerprint published outside this repository):

   gpg --recv-keys 4CB08BD1D0B3281613DD15DB1DCCDF47FEEDEEEF     # or import it from a trusted copy
   gpg --verify SHA256SUMS.asc SHA256SUMS

3. Write to USB (8 GB or larger; the ISO is hybrid: UEFI and legacy BIOS):

   Linux:   sudo dd if=orionx-phoenix-edition-v3.0.0.iso of=/dev/sdX bs=4M status=progress conv=fsync
   macOS:   sudo dd if=orionx-phoenix-edition-v3.0.0.iso of=/dev/rdiskN bs=1m

Do not flash a single .part-* file. It is not bootable on its own.