Agent handoff - state as of 2026-08-25¶
Working notes for agents (and humans) picking up AryaOS and the snstac fleet. Supersedes the 2026-05-16 handoff in portal.md.
2026-08-25 existing-host provisioning and DragonOS conversion¶
- The Ansible path now provisions a complete AryaOS appliance on an existing
Debian 13 host instead of relying on pi-gen stages to have already populated
the root filesystem. It installs the current signed sensor stack and Cockpit
plugins, builds and installs the local
aryaos-overlay, carries the portal, hardening, GutCheck, COT detail, time bootstrap, and authenticated TAK import integration, and handles current Debian Docker and Node-RED installation. These changes advance the appliance overlay to 2.3.1; existing active Node-RED flows are retained during an in-place conversion. - Existing operator networking is preserved. A configured
eth1profile wins over the packaged AntSDR fallback, which now has autoconnect priority-100. AntSDR health and HIL derive the peer from the configured DJI bind address, supporting both the AryaOS.1/.2link and an existing.9/.10/30. The capability scanner uses that derived peer and dev discovery accepts GutCheck capability dictionaries that identify entries withkey. - Existing-host DroneCOT provisioning now has image-stage parity: explicit DJI,
Wi-Fi, BLE, and DroneScout units and defaults, serial readiness and udev
rules, the AntSDR health timer, and the generic ambiguous
dronecot.servicemask. Sensor users retain the supplementary device-access groups they need. ADSBCOT always receivesfile:///run/adsb/aircraft.json, even on a node whose active role does not enable ADS-B. - A generic DragonOS Pi 5 was converted in place and personalized as
aryaos-9a9a. Itsdragonaccount, home directory, SDR tools, Tailscale state, and operator NetworkManager profiles were preserved. A root-only pre-conversion backup remains under/var/backups; the old install-media swapfile was moved into that backup and the live appliance uses only 4 GiB RAM-backed zram. The node advertisesdjiandridthrough GutCheck, runs both the AntSDR DJI and DroneScout paths, and acquired a stratum-2 clock from an AryaOS MANET peer after reboot. - Closing validation found zero failed units. The integration suite passed all modules (the Node-RED dependency check now uses privileged read access to its deliberately private runtime tree), 39 focused unit tests passed, Ansible syntax validation passed, and a five-minute burn-in completed 10/10 probes with no restarts, throttling, filesystem alerts, or failed units; peak CPU temperature was 45.2 C. TAK enrollment was attempted without persisting the enrollment URL, but the server rejected the supplied one-time token; a fresh server-issued token is still required.
2026-08-21 GutCheck discovery and explicit DroneCOT DJI development tree¶
- GutCheck 0.4.0 now owns AryaOS neighbor discovery: rich CoT plus
identity-only
_aryaos._tcp.local.DNS-SD and SSDP. It writes the compatible portal cache at/run/gutcheck/neighbors.json; the old root-runningaryaos-neighbordimplementation is retired during overlay upgrades. - DHCP-less Ethernet discovery relies on the optional, default-enabled IPv4LL fallback. CoT and SSDP transmit on every eligible active IPv4 interface.
- Dev-device tooling has no static lab address or required SSH alias. It sends GutCheck SSDP searches while listening for LINCOT CoT, expands the resulting seeds through the GutCheck neighbor cache, and requires an explicit selector when more than one device is present.
- AryaOS overlay 2.2.0 replaces the ambiguous generic DJI service with
dronecot-dji.serviceand/etc/default/dronecot-dji. The upstream package, executable, and user remain nameddronecot; the upstream generic unit is masked and has no alias. Upgrade migration preserves existing DJI settings and enabled state. - The SSH pre-auth banner is now a full authorized-use notice installed with
CRLF line endings for Windows clients. Local console, MOTD, and the landing
page carry matching language; the support URL is
https://aryaos.org. - Component release order before the next image build: GutCheck 0.4.0,
cockpit-dronecot 1.2.0, package-index refresh, then AryaOS 2.2.0. The overlay
deliberately depends on GutCheck >= 0.4.0, so an image cannot silently ship
the old discovery implementation. GutCheck's Makefile package targets are
version-specific so an existing
deb_dist/cannot rebuild an older release.
2026-08-16 zeroize credential and target closure¶
- AryaOS overlay 2.1.19 closes two live-test zeroize gaps. Zeroize now
replaces and expires the
pipassword, locks every other interactive local account and root, removes all local SSH authorized keys and the lab sudo grant, and erases shell histories. A reset unit returns to the published bootstrap password but requires it to be changed at the next login. - Zeroize now wipes the active site and COTBridge configuration before restoring the packaged defaults. This removes the prior TAK Server target as well as its TLS credentials, rather than leaving an unusable endpoint string behind.
- Restoring an older full backup after zeroize now reconciles the deliberately
excluded per-device web certificate. If the restored first-boot marker exists
but Lighttpd's combined PEM does not, the restore helper regenerates the PEM
before restarting services; otherwise it clears the marker so first boot can
retry. A live
.45restore with the PEM intentionally absent regenerated it, returned Lighttpd to active, and passed another complete strict HIL run. - A destructive live zeroize on AryaAir
192.168.0.45proved that the sentinel password hash was replaced and expired, SSH keys and lab sudo access were removed, packaged site/COTBridge defaults were restored byte-for-byte, and TAK TLS material was gone. The retained root session then restored the operating configuration and lab access, rebooted the node, and a fresh post-recovery backup was created. Temporary off-device recovery material was securely removed after validation. - The final overlay package is
aryaos-overlay_2.1.19_all.deb, SHA-2561667108dc90f7ca484e9f95933d2123118d7e379292eb409a1ed829d61dfbc3c. That exact artifact is installed on.44,.45,.149, and.199. All four report zero failed units, an HTTP 200 portal, configured TAK TLS, and a healthy connected COTBridge output. All 165 local unit tests, shell checks, Ansible syntax validation, and every strict fleet HIL run passed. Evidence is in.aryaos-lifecycle/20260816T020000Z-zeroize-2.1.19-deploy/.
2026-08-14 fleet lifecycle release gates¶
- The lifecycle HIL runner now exercises encrypted backup, restore integrity, TAK enrollment, enrollment rollback, support bundles, and an allowlisted factory reset. Interrupted enrollment automatically restores the active node's full backup. Enrollment credentials and recovery material remain outside command lines and logs.
- Enrollment validates the peer certificate chain, then records either the requested DNS name or its certificate-backed short form as COTBridge's expected TLS hostname. It refuses unrelated certificate names and keeps CA and hostname verification enabled.
- COTBridge 1.0.1 closes read-only UDP ingress transports when TLS egress setup
fails, preventing reconnect attempts from leaking the local socket and
ending in
EADDRINUSE. AryaOS overlay 2.1.18 and both image/HIL gates require that COTBridge floor. - Factory reset uses noninteractive
--force-confnewpackage restoration with a bounded timeout. This prevents a hidden conffile prompt from stalling an unattended reset while still restoring packaged gateway defaults. - The burn-in runner now records network and USB evidence and has an enforced acceptance evaluator for service health, restarts, storage, temperature, network continuity, portal responses, and decoder activity.
- The ADS-B pi-gen package list no longer explicitly requests unused
uuid-runtime. With the temporary Bookworm dependency source enabled for FlightAware, that request selected Bookworm 2.41-5 against Trixie's security-updated 2.41.5 libraries and blocked every image build. - The image release workflow marks SemVer prerelease tags such as
v2.0.0-rc1as GitHub prereleases even for field-safe builds; stable SemVer tags remain normal releases.
2026-08-14 DragonEgg position latency¶
- DragonEgg
192.168.0.149had a healthy live 3D GPS fix, but the landing CGI waited about seven seconds for an arbitrary 40-report ceiling and the Cockpit AryaOS location card requested 12 gpspipe reports. The CGI now exits on a complete TPV/SKY snapshot with a three-second worst-case bound, accepts gpsd's compactnSat/uSatcounters, and retains partial/no-fix behavior. - Sibling
cockpit-aryaosrequests eight reports, measured at about 0.7 seconds on this receiver while retaining both TPV and SKY. Package2.0.2-1(sha256:2128f6c4e5c941a6c6ac01df060b922c531372391b9fa2eaca079c4aaa7d9b21) is installed on.149; the image and HIL floors now require 2.0.2. - Five warmed live CGI samples returned in 0.42-0.95 seconds with a current 3D position and eight used satellites. The first request immediately after a lighttpd reload was a separate 9.6-second cold-start outlier. GPSD, GPSCOT, LINCOT, ACARSDEC, and ACARSCOT all remained active with zero restarts.
2026-08-14 DragonEgg LimeSDR portal inventory¶
- The landing portal now recognizes a LimeSDR Mini by its
Lime MicroUSB descriptors on the shared FTDI FT6010403:601fbridge without opening the SDR. Its radio row exposes structuredfrequency_range_mhzmetadata and the UI renders the published 10-3,500 MHz range in a dedicated Coverage column. Generic FT601 devices are not classified as LimeSDRs. - Unit coverage exercises both the Lime match and the generic-FT601 rejection; HIL requires the identity and range whenever a LimeSDR Mini is present in sysfs. The focused Python, shell, and JavaScript checks pass.
- The three portal assets are deployed on DragonEgg
192.168.0.149. Live JSON reports the LimeSDR Mini, serial1DBB4189078E3F, and the expected range. The sensor strip now includes ACARS gateway state plus a hardware-backed SDR chip; the active ACARS path makes the Sensors hero read1/1, while the SDR tooltip identifies the Lime and its coverage. ACARS decoding remained active with zero restarts through deployment.
2026-08-14 AryaAir TAK enrollment repair¶
cockpit-aryaos2.0.0 placed the services-card reorder before the$DOM helper declaration, so the whole AryaOS Site script stopped at load and the Enroll button had no listener. The siblingcockpit-aryaossource now moves that statement after the helper and includes a Node startup-preamble test; local package2.0.1-1is installed on192.168.0.199.- The first live enrollment then exposed an
aryaos-import-tak-dppartial-write bug:import_package()usedschemeafter installing TLS and writing the COTBridge lane but before assigning it, so it failed before updating shared config or restarting COTBridge. Overlay 2.1.16 assigns the scheme before any writes and adds an end-to-end connection-package regression test. The local package digest issha256:95fad1df565b8db3c5ee5a45de15cc0f61560f41a740835ecd970f83d880d109. .199is enrolled totls://takserver.snstak.com:8089. The server certificate SAN istakserver, so the lane pinsPYTAK_TLS_SERVER_EXPECTED_HOSTNAME=takserver; CA and hostname verification remain enabled. COTBridge is healthy and connected with rising RX/TX counters and zero write errors.- HIL now compares the configured AryaOS output with the COTBridge site-output
lane instead of requiring factory Mesh SA, and configured TAK nodes must show
a healthy connected runtime lane. Closing strict HIL passed all 13 modules;
evidence is in
.aryaos-burnin/20260814T161836Z-aryaair-199-tak-enrollment-closing/.
2026-08-13 CoT naming and health cutover¶
- Runtime and package identities are now COTBridge, GPSCOT, and GDLCOT. The old service, executable, package, config, and Cockpit names are not aliases. Package post-install scripts perform a one-time config migration and stop the old units.
- Local gateways continue to write to the fixed private bus
udp+wo://127.0.0.1:28087. Operators editARYAOS_COT_OUTPUT_URL, backed by COTBridge[lane:site-output]; advanced lane editing remains in the COTBridge plugin. - The shared PyTAK 7.5 status contract adds normalized
health,input, andoutputblocks.aryaos-health status --jsonaggregates current daemon files and marks data older than 30 seconds as faulty. - ADS-B config now distinguishes
ARYAOS_ADSB_1090_SOURCE,ARYAOS_ADSB_1090_DEVICE, andARYAOS_UAT_978_DEVICE, including ADSBee and independent 1090/978 selection.
Fleet rollout and upgrade-path fixes¶
- Public releases are PyTAK 7.5.2, COTBridge 1.0.0, GPSCOT 2.0.1, GDLCOT
2.0.1, SiKW00FCOT 1.0.2, DroneCOT 2.3.9, Cockpit
COTBridge/GPSCOT/AryaOS 2.0.0, and LINCOT 1.3.8. The signed
package repository now indexes the renamed public repositories instead of
their legacy names. Gutcheck remains private and must not be added to the
public
snstac/packagesproduct list; authorized lab deployments use its authenticated release asset. - Gutcheck 0.3.5 displays normalized local gateway and per-instance health. It
reads public status files directly and falls back to the exact protected
sudo -n /usr/local/sbin/aryaos-health --jsoncommand for daemon-owned0600files. The sudo rule exposes only normalized, read-only health data; Gutcheck remains unprivileged. Debian installation also generates a stable, protected per-host web token. The service remains opt-in because only one mesh node should own external alerting, but dashboard-only instances are enabled on the current lab fleet. The API and dashboard retain the AryaOS capability, decoder, clock, Bluetooth PAN, and gateway activity fields. Active gateways without runtime telemetry remain visible as unknown, while disabled roles are omitted. DroneScout receive and emit counters are shown directly. Mixed-version beacon aliases that differ only by anaryaos-prefix on a 32-character machine ID collapse to one entity; unrelated UIDs remain unchanged. - DroneCOT 2.3.9 gives each systemd instance its own status namespace through
STATUS_APPandSTATUS_PATH. This fixes the mismatch between thedronecot-dronescoutruntime directory and the former hard-codeddronecotstatus path. The DroneScout status files now survive normal service starts and appear in Gutcheck with live receive and emit counters. - AryaOS overlay 2.1.15 includes the canary and reboot fixes: it packages
aryaos-health, feeder ordering drop-ins, the protected Gutcheck collector, and independent site-output and ADS-B keys without replacing operator configuration. It keeps serial discovery off a verified ADSBee Beast port, ordersreadsb.serviceafter serial assignment, and migrates enabled legacy COTBridge lanes to onesite-outputlane while disabling the old sections to prevent duplicate CoT. Its SiKW00FCOT systemd drop-in resets and rebuilds the environment-file order under/etc, so a vendor package upgrade cannot discard the site-wide CoT input while service-local overrides still win. Repeated serial discovery also preserves a present, non-conflicting GPS assignment by stable by-id path. This avoids reopening a verified CP2102N receiver, its unsupported eight-second hardware PURGE timeout, and an unnecessary gpsd/GPSCOT interruption; missing or changed hardware still gets full protocol discovery. Overlay upgrades now migrate only missing gpsd keys instead of restoring the factoryDEVICES=""template over a live receiver. Gateway health now includes systemd enablement and live unit state. Disabled inactive roles do not degrade the appliance, while an enabled failed or inactive unit overrides a stale healthy status document. An active gateway without a status contract remains visible as unknown. The fallback neighbor beacon now uses the same bare machine ID as LINCOT so new nodes do not create duplicate fleet entities. Full configuration backups now retain the private Gutcheck defaults and web token plus the local ACARS decoder settings. Shareable--no-secretsbackups continue to omit the secret-bearing Gutcheck file while retaining the decoder configuration. The landing portal now points operators to Admin for TAK connectivity configuration while retaining the security boundary that keeps mutation off the unauthenticated page. - Node-RED now locks
socket.io-parser4.2.7, the first release that fixes GHSA-2m8v-j782-fhvr. Image verification and strict live HIL enforce that floor. Dependabot alert 75 is closed as fixed, and security workflow31758220131passes both the Python documentation and Node-RED npm jobs. - Current lab nodes are
192.168.0.44(AIS),192.168.0.45(ADSBee, DS110, GNSS), and192.168.0.199(ADSBee, DroneScout, GNSS)..44and.45run overlay 2.1.15;.199runs the enrollment-fix overlay 2.1.16. All three use PyTAK 7.5.2, COTBridge 1.0.0, GPSCOT/GDLCOT 2.0.1, SiKW00FCOT 1.0.2, LINCOT 1.3.8, DroneCOT 2.3.9, Gutcheck 0.3.5, andsocket.io-parser4.2.7. A single controlled reboot changed every boot ID; all 13 strict HIL modules then passed on every host. Node-RED flows, settings, and package manifest retained their pre-upgrade hashes..45and.199report healthydronecot-dronescoutinstances in Gutcheck with rising counters and zero write errors;.44reports its COTBridge, GPSCOT, LINCOT, and AISCOT gateways. - A paced test delivered all 5,000 generated CoT events per node at about 675
events per second with zero COTBridge write errors. A 50,000-event burst
exercised UDP saturation without service failure. Four-core CPU load peaked
at 73.3 C on
.44, 74.9 C on.45, and 49.1 C on.199, withthrottled=0x0everywhere and no core-service restarts. - PyTAK 7.5.2 exposes
supervise_with_reconnect()for gateways with custom worker graphs. GPSCOT 2.0.1, GDLCOT 2.0.1, and SiKW00FCOT 1.0.2 use it so a transient remote outage or local firewall replacement rebuilds fresh transports without exiting the daemon. Fatal configuration and certificate errors remain fatal. - Live recovery testing repeatedly reloaded firewalld on all three nodes. On
.45, eight reloads reproduced UDPEPERMin both GPSCOT and DroneCOT; both logged a bounded retry, rebuilt their transports, and resumed rising counters with their original PIDs andNRestarts=0. Four reloads on.199produced the same DroneCOT recovery, again without a PID change or systemd restart. Four reloads on.44left GPSCOT and AISCOT active with unchanged PIDs and zero restarts. Evidence is in thepytak-7.5.2-*-recovery-*.logfiles in the burn-in directory. - A deliberate
.45COTBridge output outage also left the service active with zero restarts and correctly reporteddegradedandretrying. Restoring the output returned it tookandconnected, with traffic flowing again. - The planned eight-hour run was stopped at the operator's request to prioritize
the closing software deployment. The primary sampler still collected 2,037
successful observations over 5 hours 39 minutes, 679 per host, with no probe
failures, failed units, throttling, filesystem alerts, or automatic service
restart growth. Peak temperatures were 65.55 C on
.44, 65.55 C on.45, and 40.8 C on.199. The expanded sampler collected another 1,482 successful observations, 494 per host. During the primary window,.45DroneScout received 123,583 records and emitted 247,166 events;.199received 116,147 and emitted 232,294..44AISCOT received 85 records and emitted 64 events. Every observed gateway write-error range remained[0,0]. - Burn-in evidence is collected under the gitignored
.aryaos-burnin/20260813T1907Z-post-2.1.4/directory. Checksummary.jsonand the per-node HIL logs before drawing conclusions. The directory name records the starting deployment; the nodes were upgraded in place to overlay 2.1.15, PyTAK 7.5.2, GPSCOT/GDLCOT 2.0.1, SiKW00FCOT 1.0.2, DroneCOT 2.3.9, Gutcheck 0.3.5, andsocket.io-parser4.2.7 after sampling stopped. Closing strict HIL logs areclosing-2.1.15-hil-{44,45,199}.log; all modules pass..44has no warnings and observes live AIS NMEA..45and.199only warn that their disabled AIS role is inactive and that no ADS-B aircraft were present during the closing sample. The exact CI release package was then reinstalled on all three hosts;release-2.1.15-hil-{44,45,199}.logrecords the same all-module pass. Full live backups include both/etc/default/gutcheckand/etc/default/acarsdec; shareable backups exclude Gutcheck while retaining ACARS decoder settings. Image workflow31736340576exposed an escaped-regex bug in the mounted-image verifier; commit9b96407fixed it, and replacement run31738934689passed image creation, mounted-image verification, SBOMs, tag creation, and release publication. Runs31741703758and31741941854were superseded while live HIL exposed the SiK drop-in and gpsd upgrade-path defects. Final image workflow31743281559built commit2a24944and passed image creation, mounted-image verification, SBOM generation, tag creation, and release publication. Prereleasev2026.08.13.211809-2a249441c77e-devcontains the resulting image, overlay 2.1.10 package, image metadata, and both SBOM formats. - Image workflow
31755011645built commit3421047and passed all image creation, upload, mounted-image verification, SBOM, tag, metadata, overlay, and release steps. The mounted verifier reported 315 checks passed and zero failed. Prereleasev2026.08.14.000533-342104777806-devcontains the image, overlay 2.1.12, image metadata, and SPDX and CycloneDX SBOMs. The release tag resolves to the exact implementation commit. - Image runs
31757974913and31758220090were canceled as superseded after the live backup audit found missing ACARS decoder coverage and closing HIL found the landing portal configuration dead end. Overlay 2.1.15 contains both fixes. - Authoritative image workflow
31759507279built commitcced9da, passed 317 mounted-image checks with zero failures, generated SPDX and CycloneDX SBOMs, and published prereleasev2026.08.14.012330-cced9dae79da-dev. Itsaryaos-overlay_2.1.15_all.debdigest issha256:dd39aab638f1459f9a7fd94433d7078e8bc126cba41850b4fd4c1022b67dca7a; that exact asset is installed on.44,.45, and.199.
Looking for what to work on next?
Outstanding work and follow-ups live in Roadmap & next steps. This handoff covers the running build/merge state and architecture invariants.
2026-08-12 DroneScout binary MAVLink CRLF recovery¶
One-hour AryaAir/AryaSea acceptance after 2.0.25 rollout¶
192.168.0.44(AryaSea) and192.168.0.45(AryaAir) completed a paired one-hour burn-in after upgrading toaryaos-overlay 2.0.25anddronecot 2.3.8-1. The sampler collected 720 successful probes, 360 per host, with no probe failures, failed units, service drops, restart-count growth, throttling, filesystem alerts, or boot-ID changes.- AryaSea peaked at 62.8 C, load 0.71, 11.43% memory, and 23.11% disk usage;
memory moved +0.57 percentage points. AryaAir peaked at 63.9 C, load 1.06,
6.33% memory, and 23.13% disk usage; memory moved +0.33 points. Both root
filesystems stayed clean. The only warning was the known Broadcom Wi-Fi
management-IE
-52message, with 30 unique events per host. - AryaSea kept AIS-catcher and AISCOT active in all 360 samples. Its gateway
counters were quiet during the exact sampler window, but the post-burn-in
strict suite observed live AIS NMEA. AryaAir kept readsb, ADSBCOT, and
dronecot-dronescoutactive in all 360 samples. Its DS110 added 24,330 received records and 48,660 emitted events with zero DroneCOT restarts. - All 13 strict HIL modules passed on both hosts after the soak. Evidence is in
the gitignored
.aryaos-burnin/20260813T022127Z-aryaair-aryasea-1h/directory. The authoritative health result issummary.json; final suite logs arepost-burnin-hil-44.logandpost-burnin-hil-45.log. -
AryaOS commit
e23106apassed pull-request validation run31657308366and image run31657314290. The latter completed image creation, mounted-image verification, SBOM generation, tag creation, and release publication. -
Fresh AryaAir host
192.168.0.45has an ADSBee, a BlueMark DroneScout DS110 on the ESP32-S3 USB CDC path, and a CP2102N GNSS receiver. AryaOS discovery now identifies the live DroneScout from checksum-valid MAVLink heartbeat andOPEN_DRONE_ID_MESSAGE_PACKtraffic and appliesadsb rid. The dedicateddronecot-dronescoutinstance is enabled and the landing portal reports UAS active. - A byte-for-byte 30-second capture found 250 nominal MAVLink frames. The DS110
USB output expanded every LF byte to CRLF, including LF bytes inside binary
MAVLink headers, payloads, and checksums, and appended a newline after each
frame. Most apparent pymavlink
BAD_DATAwas the harmless frame delimiter, but 12 of 250 frames were checksum-invalid because an embedded LF had been expanded. Reversing CRLF to LF recovered all 250 frames with valid checksums: 220 OpenDroneID packs and 30 heartbeats. - DroneCOT
v2.3.8, commitb90850d, adds opt-inSERIAL_CRLF_NORMALIZE=1. The streaming filter preserves state across serial read boundaries and defaults off for compliant receivers. Unit coverage includes every split point through expanded CRLF pairs and an end-to-end pymavlink checksum regression. The canonical suite passes 106 tests with one skip and 14 subtests; targeted Black and flake8 checks pass. - AryaOS 2.0.25 enables the workaround only in
/etc/default/dronecot-dronescout. Image verification now requires DroneCOT 2.3.8 and that setting. Live HIL on.45with the locally builtdronecot_2.3.8-1_all.debdecoded 329 RID records in 45 seconds, matching the 330 expected from the raw rate within the sampling boundary. CoT for lab RID1787F04BM24010011195reached COTBridge with current position. The service remained enabled and active with zero restarts, no failed units, and no Pi throttling. - The same host passed all 13 strict AryaAir HIL modules after the DroneCOT and
overlay upgrade. DroneCOT PyPI workflow
31656496938and Debian release workflow31656496947both succeeded; releasev2.3.8containsdronecot_2.3.8-1_all.deb. Signed package repository workflow31656860708published 2.3.8 for fleet updates. - When installing a locally built DroneCOT package on an existing AryaOS box,
preserve its modified
/etc/default/dronecotconffile explicitly, for example withdpkg --force-confold --configure dronecotif a noninteractive local-package install stops at the conffile prompt.
AryaAir/AryaSea fleet update and acceptance¶
- AryaOS commit
e23106ascopes CRLF normalization to protocol-verifiedesp32-usbRemote ID transports. The role manager writes0for compliant UART transports, and the overlay migration enables it only when the live/dev/dronescoutudev vendor is Espressif (303a). The complete 120-test repository suite, Ansible syntax check, shellcheck, overlay package build, and PR validation run31657308366pass. Image run31657314290completed all build, mounted-image verification, SBOM, and publication steps from that implementation commit. Releasev2026.08.13.013732-e23106aa5fac-devcontains the resulting image and overlay. 192.168.0.44(aryaos-b6b9, AryaSea) and192.168.0.45(aryaos-fdb9, AryaAir) now run overlay 2.0.25 and DroneCOT 2.3.8. The update retained all role, GNSS, AIS, ADS-B, and gateway configuration hashes and preserved service enablement. AryaSea hasSERIAL_CRLF_NORMALIZE=0and AryaAir's ESP32-S3 DS110 hasSERIAL_CRLF_NORMALIZE=1. Neither host required a reboot.- Both hosts passed all 13 strict HIL modules before and after a 15-minute
paired acceptance soak. The sampler collected 180 successful probes, 90 per
host, with no probe failures, failed units, service drops, restart growth,
throttling, filesystem alerts, or boot-ID changes. AryaSea peaked at 61.7 C,
load 0.07, 11.13% memory, and 23.11% disk. AryaAir peaked at 60.05 C, load
0.59, 5.98% memory, and 23.13% disk. Memory changed only +0.25 and +0.13
percentage points respectively. The only journal warning was the known
Broadcom Wi-Fi management-IE
-52message. - AryaAir decoded 6,173 live Remote ID payloads during the final 15-minute
window. The current DroneScout process had zero restarts and no checksum,
traceback, bad-data, or runtime errors after startup; the portal reported
UAS up through
dronecot-dronescout. AryaSea received one live AIS NMEA line near the end of the run; AIS-catcher and AISCOT remained active with zero restarts. Evidence is gitignored under.aryaos-burnin/20260813T012330Z-aryaair-aryasea/, with the authoritative result inacceptance-sampler-15m/summary.json.
2026-08-12 latest-firmware AryaAir/AryaSea regression follow-up¶
- Fresh-image testing on
192.168.0.44exposed a discovery dependency: its quiet CH340 dAISy could only be assigned after AIS was already enabled, while first boot only enabled AIS after discovering an assigned receiver. The capability scanner now recognizes the constrained AryaSea layout of one CH340 beside a separately verified GPS, and explicitly refuses that guess when an AntSDR is present. Live HIL with the AIS assignment temporarily cleared returnedaisas an auto-applied capability and selected the correct stable by-id path. - The same boot produced one AISCOT restart. PyTAK correctly rebuilt the client after a refused COTBridge connection, but AISCOT did not close its UDP/5050 listener before the replacement worker bound the same port. AISCOT 7.3.1 retains and closes the datagram transport through the PyTAK worker cleanup hook. Its regression starts a replacement worker on the same port in the same process. AryaOS 2.0.24 and both image/runtime checks require AISCOT 7.3.1 or newer.
- AISCOT PR 17 merged as
19c82a5; releasev7.3.1producedaiscot_7.3.1-1_all.deb, and signed repository run31638850105published it for arm64 and armhf. AryaSea was upgraded to AISCOT 7.3.1 and AryaOS overlay 2.0.24. The installed package closed and rebound the same UDP port in one process, survived a 70-second COTBridge outage with the same PID and zero systemd restarts, and retained UDP/5050. After reboot, the six AIS/GPS/CoT services were active with zero restarts, no failed units or throttling, and all 13 strict HIL modules passed. The final RF window was quiet. - The first 2.0.24 image attempt, run
31639680637, reached the Node-RED stage and received HTTP 503 from the pinned GitHub release asset. Run31640434386proved that the browser-facing release CDN remained unavailable through all bounded retries. The stage now fetches the same immutable asset through its GitHub release API id, retains retry and pinned SHA-256 verification, and CI downloads and verifies the payload during its preflight.
2026-08-12 AryaAir/AryaSea eight-hour burn-in¶
192.168.0.199(aryaos-d628, AryaAir) and192.168.0.44(aryaos-c2cb, AryaSea) completed an eight-hour mixed hardware-in-the-loop acceptance run. The sampler collected 960 successful probes (480 per host) with no probe failures, failed units, required-service drops, restart-count growth, throttling, filesystem alerts, or boot-ID changes. The role services were active in all 480 samples on each host: ADS-B/DroneScout on AryaAir and AIS on AryaSea.- AryaAir peaked at 61.15 C, load 4.46, 21.66% memory, and 23.15% disk usage;
memory moved -0.29 percentage points. AryaSea peaked at 78.75 C, load 2.06,
17.62% memory, and 23.93% disk usage; memory moved +1.31 points. The only
repeated kernel warning was the known Broadcom Wi-Fi management-IE
-52message. - Two 512 MiB discard-only network passes measured AryaAir at 30.84--35.64 MiB/s upload and 56.66--63.09 MiB/s download, and AryaSea at 32.51--37.88 MiB/s upload and 54.85--62.16 MiB/s download. AryaAir completed both 15-minute 4-worker/512 MiB load phases at no more than 62.8 C. AryaSea's guarded tests intentionally stopped four workers at 78.2 C and two workers at 78.75 C, with no throttling or service fault; its 15-minute 1-worker/512 MiB phase passed at 73.8 C. Treat one sustained CPU worker as the safe current thermal envelope for the installed AryaSea enclosure.
- Live DroneScout traffic exposed a GDLCOT crash loop: legitimate unknown CoT
fields arrived as
hae="nan"andspeed="nan", and GDLCOT attempted to convert them to integers. GDLCOT 1.0.1 rejects non-finite coordinates and treats non-finite altitude/motion as unknown. Its 60-test suite and flake8 pass, upstream PR 2 is merged asb57f35c, release/package1.0.1-1is in the signed repository, and both live hosts now carry it without changing their local configuration. AryaAir processed the same Remote ID stream with zero subsequent GDLCOT restarts; AryaSea retains GDLCOT disabled/inactive as intended for its role. - A long-running DroneScout receiver can rotate its one-time MAVLink heartbeat
line out of the RAM journal even while processing current Remote ID payloads.
HIL now accepts either the startup heartbeat or live
Processing RID dataas MAVLink session proof. The final strict HIL suite passes every module on both hosts; ADS-B and AIS were RF-quiet during the final short windows, but service ownership, ports, role state, and restart checks passed. Earlier in the run, live/synthetic role traffic exercised both complete pipelines. - AryaOS commit
4c6f0c3requiresgdlcot >= 1.0.1in HIL and mounted-image verification;965013eadds the journal-safe DroneScout HIL assertion and this handoff. Final image run31612196240passed every build, verification, SBOM, and publication step and releasedv2026.08.12.154348-965013ee9dd1-dev. Detailed gitignored evidence is under.aryaos-burnin/20260812T020135Z-aryaair-aryasea/; the authoritative sampler result isacceptance-sampler/summary.jsonand the final strict-suite logs arefinal-hil-aryaair.logandfinal-hil-aryasea.log.
2026-08-11 chronos GPSCOT provisioning¶
chronosis a Raspberry Pi Zero W at192.168.0.200, running 32-bit Raspberry Pi OS Bookworm. Usegbaand the AryaOS development SSH key.playbooks/gpscot-generic.ymlis the minimal, repeatable provisioning path. It assigns the PL011 to a GPIO14/15 GNSS receiver, disables Bluetooth and the serial console, installs only gpsd/GPSCOT from the signed snstac repository, and broadcastsGPSCOT-chronosCoT on UDP/4349.- Run it with
ansible-playbook -i inventory.yml playbooks/gpscot-generic.yml --limit chronos. Cockpit, LINCOT, COTBridge, and the rest of the AryaOS sensor stack are deliberately outside this host profile. - Provisioning installed
gpscot 1.0.1-1andpytak 7.4.3-1. gpsd identified the receiver as an MTK-3301 at 9600 baud and reported a mode-3 fix with 11 of 13 satellites used. A LAN capture verifiedGPSCOT-chronosCoT from192.168.0.200, including GNSS-derived CE/LE, altitude, course, and speed. - HIL passed a forced gpsd restart without restarting GPSCOT, a 12-sample soak
with a continuous 3D fix and zero service restarts, an idempotent playbook run
(
changed=0), and a second reboot. The post-reboot host had no failed units, no Pi throttling, and about 284 MiB available memory. - Original boot files are retained as
config.txt.pre-gpscotandcmdline.txt.pre-gpscotunder/var/backups/aryaos-gpscot. To roll back the UART reassignment, stop/disable GPSCOT, restore those two files to/boot/firmware/, re-enablehciuart.service, unmask any needed serial-getty unit, and reboot. Restoring the originals re-enables the serial console and returns the PL011 to Bluetooth.
2026-08-11 .44 refresh and AIS restart hardening¶
192.168.0.44(aryaos-c2cb, Raspberry Pi 5) was refreshed from overlay2.0.18to2.0.23, and all available OS and Cockpit gateway package updates were installed. The host now has the fixed scrolling/branding gateway builds documented below. Its GPS, AIS, and site configuration hashes were unchanged.- Repeated first-boot serial discovery exposed a live-service race: the helper
rewrote already-correct AIS values and requested another AIS-catcher restart
while its first start was still probing optional backends. AIS-catcher deferred
SIGTERM, so the unit remained
deactivatinguntil systemd's 90-second default stop timeout. Serial assignment now detects exact no-op writes, tracks AIS changes independently from GPS, and restarts AIS-catcher only when its port or baud actually changes. A 15-second stop timeout bounds a genuine reassignment. - A clean reboot retained the stable CP2102N GPS and CH340 dAISy paths. GPSD had
a 3D fix, AIS-catcher/AISCOT/COTBridge were active with zero restarts, the AIS
dashboard answered on TCP/8100, and no systemd unit failed. A checksum-valid
synthetic type-1 report produced
MMSI-366967102CoT at COTBridge's UDP/28087 ingress, exercising the complete decoder-to-CoT path while RF was quiet. - Strict HIL passed all 13 modules. A three-minute, 12-sample burn-in had zero probe failures, service drops, restart increments, throttling events, storage alerts, or boot-ID changes; peak temperature was 60.05 C, peak load was 0.34, and memory moved 0.39 percentage points. Remaining warnings were boot-time Docker/firewalld stale-chain cleanup, normal Broadcom Wi-Fi driver noise, two recovered CP210x setup timeouts, and chrony correctly rejecting the NMEA-only GPS clock's 333 ms offset in favor of network time.
2026-08-11 Cockpit gateway scrolling sweep¶
LINCOT stylesheet follow-up¶
- LINCOT had the same design-kit SCSS and React layout as the other gateways,
but its shipped
index.htmlwas the only one that did not loadindex.cssor Cockpit's sharedbranding.css. The UI therefore looked legacy/unstyled even though the correct CSS and fonts were present in the package. cockpit-lincot1.1.3 adds both links and a source regression. AryaOS HIL now verifies the two stylesheet links for all seven gateway plugins, in addition to checking their compiled CSS and root scroll containers.- LINCOT release run
31529704293and signed repository publish run31529773872completed successfully. The public arm64 index advertisescockpit-lincot 1.1.3-1under the existing verified packaging key. .199was upgraded only fromcockpit-lincot 1.1.2-1to1.1.3-1./etc/default/lincotretained SHA-25646554bbb6b92be73e92de33ab80b8bef79d4ffdc0d04dfee470eb3f7bb82d7b8,lincot.servicestayed active, and the complete strict HIL suite passed, including all seven new installed-HTML stylesheet checks.-
AryaOS image run
31530016764completed successfully from4b21257; its mount-based verifier enforcedcockpit-lincot >= 1.1.3. Releasev2026.08.11.201034-4b212576cac2-devcontains the 1.62 GB compressed image, image hashes, overlay package, and SPDX/CycloneDX SBOMs. -
Cockpit fixes non-index page bodies in place, but the seven plain-root gateway plugins did not provide their own scroll container. Expanding Debug Logs or Advanced Details could therefore expose content below the viewport with no way to reach it.
#appnow owns vertical scrolling in ADSBCOT, AISCOT, APRSCOT, COTBridge, DroneCOT, LINCOT, and SAPIENTCOT. - Every plugin has a compiled-Sass regression for the viewport-height root and
overflow-y: auto; the browser-enabled gateway suites also expand Debug Logs and prove the root can scroll. AryaOS HIL checks both the minimum fixed package versions and the installed (possibly gzip-compressed) CSS rule. - Fixed release floor: cockpit-adsbcot 1.2.3, cockpit-aiscot 1.2.3,
cockpit-aprscot 0.1.1, cockpit-cotbridge 1.2.2, cockpit-dronecot
1.1.3, cockpit-lincot 1.1.3, cockpit-sapientcot 0.1.1. The three
direct GitHub download pins in
stage-aiscotmatch those releases; the other plugins are sourced from the signed snstac apt repository. - The first APRSCOT/SAPIENTCOT tag builds exposed a workflow bug: they built the packages and then tried to upload into a Release that did not exist. Their workflows now create the GitHub Release on demand before uploading assets; the fixed tag jobs were rerun successfully.
- All seven releases were ingested by
snstac/packagespublish run31516851407. The public arm64 index contains the exact release floor above, and itsInReleasehas a good signature from packaging keyC34ED9FEFE38916133DC7B614F0D93E47D24D367. .199(aryaos-d628) was upgraded in place from the signed repository. The complete strict default-profile HIL suite passed: all seven installed CSS rules and versions, live ADSBee/GNSS/DroneScout paths, Remote ID heartbeat and payload processing, portal power/branding/capability checks, storage, and security. The update did not change gateway service enablement or config.- AryaOS image run
31517168556completed successfully fromeec008f; the mount-based image verifier passed the new package floors and the complete image content slate. Releasev2026.08.11.174209-eec008f09b26-devincludes the 1.62 GB compressed image,image-info.json, SPDX/CycloneDX SBOMs, and overlay package.
2026-08-10 .44 AIS HIL¶
192.168.0.44returned asaryaos-c2cbon image22e7a12and overlay2.0.15. Its CP2102N emitted checksum-valid GPS NMEA at 9600 baud; its one remaining CH340 serial device was silent and was therefore safely assigned as the intended dAISy by elimination when the maritime role was applied.- AIS-catcher and AISCOT ran with zero steady-state restarts. Live RF produced
checksum-valid
!AIVDMtraffic for MMSI3669708. A synthetic type-1 position report exercised the complete UDP/5050 path and produced a validMMSI-366967102CoT event at COTBridge's loopback ingress, provingserial receiver -> AIS-catcher -> AISCOT -> COTBridgeend to end. - The strict HIL suite passed every module. Storage was clean, media manufacturer
ID
0x000027was valid, the boot PARTUUID matched, and the Pi 5 kernel and initramfs artifacts passed size checks. The node had no failed units or throttling and retained a 3D GPS fix. - HIL exposed two defects fixed in overlay
2.0.18: role application used to start AIS-catcher with an empty serial argument before assignment, producing two avoidable exits, and AIS-catcher 0.68 enabled its internet community feed by default. AryaOS now enables-but-does-not-start the unit, assigns the serial receiver first, refuses to start cleanly when the assigned device is absent, bounds failures in the unit's[Unit]section, and passes-X offon serial, RTL, and generic-SDR AIS paths. HIL now requires both AIS services, stable isolated serial assignment, zero restart loops, local ports, and explicit community sharing opt-out. - Installing the overlay with AIS already active exposed an ordering deadlock:
aryaos-serial-assign.serviceis ordered before AIS-catcher/GPSD but called blockingtry-restartjobs for those same units. The restarts are now queued with--no-block, allowing the oneshot to finish before its dependents run. - A ten-minute post-fix burn-in passed 60/60 probes with one boot ID, no failed
units, no service drops/restarts, no throttling or filesystem alerts, 58.4 C
maximum temperature, 0.24 maximum one-minute load, and 0.1 percentage-point
memory drift. The sampler now tracks
ais-catcheritself as well as AISCOT.
2026-08-10 .199 reboot and factory-reset HIL¶
Replacement-image media failure (historical; card replaced)¶
- The exact
22e7a12CI image returned asaryaos-025fwith overlay2.0.15. First boot correctly detected and configured ADSBee, DroneScout, and the SiRF GPS; the default HIL suite passed every enabled software/hardware path except storage. Live DroneScout heartbeat and Remote ID payload checks passed, all enabled services were active with no failed units, and the short ADS-B sample was RF-quiet. /boot/firmware/cmdline.txtwas again 132 bytes of AArch64 instructions. The pristine release image contains the correct 139-byte command line. The corrupt bytes match/usr/bin/nodeat file offset0x19f8000exactly. On the card, boot LBA35008and root LBA2510784returned the same complete 512-byte Node sector despite belonging to different partitions. The card identifies asSD32Gwith invalid manufacturer ID0x000000.- An offline FAT check then found corrupt directory entries and reclaimed
42,062,848 bytes in seven orphaned chains. It exposed missing/corrupt Pi 5
boot artifacts, including
kernel_2712.imgandinitramfs_2712. The running root filesystem and services remain healthy, but do not reboot or factory reset this node. Replace the microSD card with reputable endurance media, flash the current image, and rerun HIL. Forensic evidence is gitignored under.aryaos-burnin/20260810T-new-firmware-forensics/. - Overlay
2.0.16replaces the upstream initramfsset_partuuidpayload at build time. The replacement constructs the new command line in tmpfs, writes a separate FAT candidate, syncs and remounts the boot filesystem, and requires byte-for-byte candidate and final-path readback (up to five allocations) before continuing. HIL now also rejects zero manufacturer IDs, binary command lines, and missing/implausibly small model-specific kernel/initramfs files. - A 15-minute post-diagnosis burn-in collected 30/30 successful probes with one
boot ID, no throttling, no failed units, no service drops or restarts, 33.65 C
maximum temperature, 0.26 maximum one-minute load, and 0.06 percentage-point
memory drift. All 30 samples correctly retained the storage alert. The only
repeated journal message was the known Broadcom onboarding-AP vendor-IE
warning (
-52). The enhanced sampler then proved it records the invalid manufacturer ID, binary cmdline, and both missing Pi 5 boot artifacts.
Current .199 replacement card and live portal capabilities¶
.199is nowaryaos-d628on a replacementGB1QTcard with valid media manufacturer ID0x00001b. A controlled reboot completed normally. The boot command line is printable and names the installed root PARTUUID;kernel_2712.imgandinitramfs_2712pass the HIL size checks. The prior no-reboot restriction applied only to the discardedSD32Gcard.- First boot discovered
ARYAOS_CAPABILITIES="adsb rid": ADSBee feeds readsb over its stable Mode-S Beast serial path, DroneScout feedsdronecot-dronescoutthrough/dev/dronescout, and the PL2303 GPS has a live 3D fix. The strict suite confirms Remote ID heartbeat and payload processing, zero failed units, clean storage, and no service restart loop. - Overlay
2.0.19fixes the HTTPS landing page's UAS state. The page used to inspect only legacydronecot.service, so a live DroneScout, Wi-Fi/BLE RID, or SAPIENT gateway appeared disabled. The UAS item now aggregates all of those live implementations and exposes their member-unit states in portal JSON. The hero SENSORS count considers only activated sensor gateways, not disabled capabilities or the always-on CoT/GNSS core. On.199, the portal now reports ADS-B and UAS/Remote ID active and healthy. - The packaged overlay was installed on
.199; the complete post-install strict HIL suite passed every module. Expected warnings were limited to deliberately disabled AIS/SiK, the absent unauthenticated TAK configuration pointer, and a brief RF-quiet ADS-B sample. Remote ID remained live. - Actions run
31465778187built commit643f5c2in 24m13s. Finished-image verification reported 281 ok, 0 failed. The image, overlay2.0.19, image metadata, and SPDX/CycloneDX SBOMs are published in prereleasev2026.08.11.065730-643f5c2d0baa-dev. - Overlay
2.0.20restores the landing page's POWER status. Debian's lighttpd sandbox hasPrivateDevices=yes, which hid/dev/vcio_gencmdeven thoughwww-datawas already in thevideogroup. The AryaOS drop-in retains the private device namespace and bind-mounts/allows only that firmware-command character device..199now reportsthrottled=0x0/ POWER OK through the HTTPS CGI. HIL asserts the telemetry block on Pi, and the UI explicitly says UNKNOWN instead of remaining blank if it becomes unavailable. Actions run31502191920built commitc8fbeadin 21m22s; finished-image verification reported 281 ok, 0 failed. Prereleasev2026.08.11.145102-c8fbead1c1e2-devcontains the image, overlay, image metadata, and SPDX/CycloneDX SBOMs. -
Overlay
2.0.21replaces Cockpit's legacy rounded teal tile and generatedAat/admin/with the exact reverse AryaOS Signal Block from the design guide. The stylesheet now uses the Console Ink, Paper, Field Green, and Signal Orange tokens, and the overlay installs the canonical SVG into both Cockpit OS-brand directories. On.199, both the served CSS and SVG match the repository byte for byte; the mark is publicly available before login at/admin/cockpit/static/mark-aryaos-rev.svg. The portal HIL module asserts the live asset, color, and CSS reference. The full local 107-test suite and Ansible syntax check pass. The strict HIL branding, portal, service, storage, and hardware checks pass. The first post-install run recorded one transient DroneScout UDPEPERMwhile the overlay reloaded the firewall; the service recovered, its counter was cleared after confirming the cause, and the full strict rerun passed with continued live RID processing and zero restarts. The first CI attempt (31508617396) correctly failed when pi-gen's container could not see the canonicaldocs/brandsource; commitad682b1adds that directory as a read-only build input and regression-tests the mount. Rerun31509326669succeeded in 23m07s with 287 ok, 0 failed from finished-image verification. Prereleasev2026.08.11.161055-ad682b1257fe-devcontains the image, overlay2.0.21, image metadata, and SPDX/CycloneDX SBOMs. -
The reflashed
192.168.0.199returned asaryaos-d600with overlay2.0.10, the ADSBee, DroneScout, and SiRF GPS all attached. Its fresh first boot wroteARYAOS_CAPABILITIES="adsb rid"but left readsb on the RTL-SDR default and enableddump978-fa; readsb, ADSBCOT, and UAT consequently failed. The scanner itself correctly protocol-verified both serial sensors. - First boot accumulated capability names across its bounded scans but invoked
the plain
aryaos-role capssetter, bypassing the transport wiring used bydiscover --apply. Overlay2.0.14addsapply-detected: first boot keeps its multi-pass union while configuring the ADSBee Mode-S Beast by-id path and colon-safe/dev/dronescoutfeed before enabling services. - Factory-reset HIL exposed two more lifecycle gaps. The helper now disables sensor units and removes both capability-autodetection markers before reboot, so scanners see unclaimed ports. It also clears the crash-guard counter and sticky safe-mode flag and restores USB power; an intentional reset reboot no longer becomes the third "short boot" and falsely powers off every sensor.
- The OTA overlay builder had omitted
aryaos-safe-mode, its units, and sensor drop-ins even though full images installed them. They are now packaged, so deployed boxes receive the factory-reset/safe-mode fix rather than only new images. Static image verification and regression coverage assert all three lifecycle contracts. - A controlled reboot changed the boot ID while preserving hostname/machine ID, the installed root PARTUUID matched the boot command line, all ADS-B/RID/GPS services recovered, and the full default HIL suite passed. readsb decoded live ADS-B traffic and DroneCOT processed the lab Remote ID beacon.
- The final network-preserving reset returned as
aryaos-265bwith a new machine ID and web certificate. The lab authorized-key and sudoers digests were unchanged,.199remained reachable, safe mode stayed off, GPS was reassigned to its stable PL2303 by-id path,adsb ridwas rediscovered, ADSBee and DroneScout transports were correct, and no units failed. The final complete HIL suite passed all modules; its short ADS-B sample happened to be quiet, while Remote ID heartbeat/payload checks remained live. - The reset's best-effort gateway reinstall failed after unpacking ADSBCOT,
DroneCOT, and LINCOT, leaving them pending in dpkg even though their running
services looked healthy. The packages configured cleanly when resumed.
Overlay
2.0.15therefore runs a bounded noninteractivedpkg --configure -arecovery on the apt failure path so reset never knowingly reboots with an inconsistent package database.
2026-08-10 TAK outage resilience (.60)¶
- A prolonged outage of the dedicated ACARSCOT TAK endpoint exposed two coupled
failures on
aryaos-ff84(.60): the WebSocket receive worker exited after the server closed it, and repeated PKCS#12 loads leaked three extracted PEMs per attempt. After 12,723 files, both 100 MiB/tmpand/var/tmpmounts were full; ACARSCOT then entered a 12,272-restart systemd loop withNo usable temporary directory. - PyTAK
7.4.3supervises transient TCP/TLS/WebSocket failures within one process, rebuilding bounded worker queues per attempt and retrying with a jittered 5-to-120-second exponential delay. A five-minute stable session resets the delay. Configuration errors remain fatal. Temporary PKCS#12 PEMs are removed immediately afterSSLContext.load_cert_chain(), including partial-conversion failure paths. - ACARSCOT
0.1.1requires PyTAK>= 7.4.3and packagesStateDirectory=acarscotplusHOME=/var/lib/acarscot, keeping enrollment state across reboots without a local drop-in. - On
.60, only the 12,723 confirmed root-level temporary PEMs owned byacarscotwere removed; the three persistent enrollment-cache files were preserved. A bounded fixture test proved initial outage, recovery, server-initiated close, and second recovery on one PID with zero systemd restarts and zero leaked PEMs. The operator's real TAK endpoint remains unreachable as of this handoff, but ACARSCOT stays active and retries safely. - The image now installs ACARS packages, requires PyTAK
>= 7.4.3and ACARSCOT>= 0.1.1, and verifies persistent state. HIL checks assert active ACARS units, zero systemd restarts, persistent HOME/state, no leaked PEMs, and headroom on/tmp,/var/tmp, and/var/log. - PyTAK
v7.4.3and ACARSCOTv0.1.1are published GitHub releases. Packages workflow run31415323491rebuilt and deployed the signed repository fromsnstac/packagesmain commit2423630; the public arm64 index was then signature-verified with the vendored key and confirmed to servepytak 7.4.3-1andacarscot 0.1.1-1(which depends onpytak >= 7.4.3). - Source validation passed: PyTAK 233 tests on the development interpreter and
its Python 3.7--3.12 CI matrix; ACARSCOT 46 tests; AryaOS 69 tests with three
intentional skips; Ansible syntax, strict MkDocs, shellcheck, Bash syntax,
and Debian package inspection. The complete
.60HIL suite passed all 12 modules on the hardened packages. - AryaOS Actions run
31415495113built commit08f3654in 22m56s. The finished-image verifier reported 264 ok, 0 failed, explicitly confirmingpytak 7.4.3-1,acarscot 0.1.1-1, persistent ACARSCOT state/HOME, and the intended default-disabled role policy. The image, SPDX/CycloneDX SBOMs, checksums, and overlay deb are published in prereleasev2026.08.10.180238-08f3654475b8-dev. - A final live outage check on
.60foundacarsdecandacarscotboth active/enabled, ACARSCOT still on PID937080with zero systemd restarts, zero leaked PEMs, zero failed units, no credential-pattern matches in its outage logs, and/tmp//var/tmpat 2%/1% used.
2026-08-10 ADSBee / DroneScout discovery HIL (.199)¶
- The newly flashed
aryaos-f069at192.168.0.199has an ADSBee 1090 on/dev/serial/by-id/usb-Raspberry_Pi_Pico_E4654C6197481B39-if00and a SiRF GSD4e GPS connected through a Prolific PL2303 UART adapter. The GPS is on/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0. Generic USB identities are not treated as product identities. - ADSBee detection is protocol-verified with the read-only
AT+BIAS_TEE_ENABLE?query. Five consecutive probes succeeded. Discovery configured readsb as--device-type modesbeaston the stable by-id path, recordedARYAOS_ADSB_1090_SOURCE=adsbee, and deliberately keptdump978-fadisabled. Repeateddiscover --applyis idempotent while readsb owns the tty. - Live receiver queries reported 1090 and sub-G receivers enabled, console
output
BEAST, trigger level1569mV (-45 dBm), offset600mV (-104 dBm), and more than 5,100 seconds of uninterrupted receiver uptime. After an initially quiet several-minute sample, readsb decoded 451 valid messages, six tracks, and 50 position updates in 9.4 minutes; three aircraft were current and ADSBCOT consumed them.readsb,adsbcot, andgdlcotare enabled/active. readsb and gdlcot have zero restarts; ADSBCOT restarted once after the controlled test stopped readsb and removed its runtime JSON tree, then recovered normally. - The PL2303 path was initially tested as a claimed DS110 and emitted no
checksum-valid MAVLink. A binary-safe capture then found checksum-valid SiRF
frames at 4,800 baud. gpsd identifies it as
SiRF, subtypeGSD4e_4.1.2-B2_RPATCH.02-F-GPS-4R. It acquired a live 3D fix with 12 satellites in view and 7 used./etc/default/gpsdnow pins the stable by-id path. AryaOS serial discovery now validates SiRF binary framing in addition to NMEA, and capability discovery excludes an assigned GPS from PL2303/DS110 probing. - The box exposed a second GPS-path defect:
gpscot.servicewas installed but disabled even though GPSCOT is documented as role-independent core plumbing. Overlay 2.0.9 enables/starts GPSCOT during installation, and HIL now asserts that it stays active. The package also reruns serial assignment after refreshing gpsd defaults, avoiding a blankDEVICESsetting after update. dronecot-dronescout.servicenow uses anExecConditionthat validates its configured serial character device. A missing/unconfigured receiver produces a clean inactive/skipped unit (start result success, no failed unit) rather than aRestart=alwaysloop.- Overlay 2.0.9 was initially installed on the box. The post-update closing HIL suite
passed 88 checks, including live GPS/portal data, GPSCOT, and ADSBee traffic;
there are no failed units. The only deferred failure is the known corrupt
binary
/boot/firmware/cmdline.txt. Do not reboot this node until the separate command-line repair is completed. - After the DroneScout was attached, discovery verified
HEARTBEATandOPEN_DRONE_ID_MESSAGE_PACKon its unique ESP32 CDC port. The first applied configuration exposed a pymavlink edge case: the MAC-address colons in the stable by-id path made pymavlink treat the tty as UDP while systemd still reported DroneCOT active. AryaOS now selects/dev/dronescoutonly when it resolves to the protocol-verified port, and refuses an unsafe colon-bearing fallback. Live HIL then received the MAVLink heartbeat, processed the lab beacon, and emitted both UAS and operator CoT withsensor_id=dronescout. A 68.8-second runtime sample counted 411 received RID records and 819 emitted events with zero write errors; a separate 10-second wire capture saw 63 UAS CoTs reach COTBridge ingress. Overlay 2.0.10 is installed, and the closing HIL suite passed 94 checks. Its only failure remains the deliberately deferred corrupt boot cmdline; do not reboot this node. - Package HIL also found a zero-corrupted
/var/lib/apt/listchangespickle at byte 983,261. The original is preserved on-host aslistchanges.corrupt-20260810and in the gitignored HIL evidence directory; Debian'sapt-listchanges.servicerebuilt a valid database and completed successfully. This did not touch the boot cmdline.
2026-08-02 four-node HIL burn-in (SOAK COMPLETE; .60 RECOVERED)¶
The eight-hour sampler ran from 09:03:45 through 17:03:45 UTC against .13,
.44, .60, and .199: 480 cycles per host and 1,920 records. Raw evidence,
enhanced summaries, intervention annotations, and final HIL/audit logs live in
gitignored .aryaos-burnin/20260802T090345Z/. Every .13/.44/.199 probe
failure is explained by a controlled reboot/package intervention or the sudo
capacity defect found and fixed below. .60 supplied 164 successful samples,
then remained offline for cycles 165--480 after its operator-triggered
filesystem-repair reboot. It returned later as a freshly initialized image;
the recovery and post-flash validation are recorded below.
Lab inventory and roles¶
| Address | Host | Active role / attached hardware | Wired link |
|---|---|---|---|
192.168.0.13 |
aryaos-36aa |
DJI DroneID; AntSDR at 172.31.100.2; ESP32-S3 + CH340 |
10 Mb/full |
192.168.0.44 |
aryaos-91bd |
Wi-Fi Remote ID; AR9271 monitor adapter + CH340 + CP2102N | 10 Mb/full |
192.168.0.60 |
aryaos-ff84 (reflashed; formerly aryaos-fad2) |
ACARS; LimeSDR Mini + u-blox 7 | 1 Gb/full |
192.168.0.199 |
aryaos-0f26 |
Gutcheck; Pico + PL2303 | 1 Gb/full |
Findings already fixed and deployed¶
- Gutcheck
v0.2.0parses AryaOS beacon v1-v5 capabilities, decoder state, clock/TDoA fields, and PAN state, and renders all four on its node table. It sustained 5,000 rich entities and 10,000 authenticated API requests without drops or restarts. AryaOS now permits its token-gated port 8181 on the trusted LAN only (never the onboarding hotspot). - PyTAK
v7.4.2uses per-app runtime status directories and serializes status writes. Dronecotv2.3.7reports DJI runtime state, preserves intentional service enablement across upgrades, and reloads changed systemd units. Lincotv1.3.7bounds the no-GPS probe and kills its process group. COTBridgev0.2.1fixes write-only UDP CPU spin, usrmerge packaging, and binary AES key handling. - All Cockpit gateway consumers use
cockpit-shared v1.3.1, which closes the four-second D-Bus client leak. Sapient/APRS packaging and dependency audits are also clean. - Capability beacon v5, bounded local SDR/serial discovery, ACARS start limits,
portal GPS probing, Wi-Fi/Bluetooth DHCP coexistence, and the burn-in sampler
are in the AryaOS branch
fix/dronecot-ws-recovery. - Raspberry Pi OS Trixie's new
rpi-swapdefaulted tozram+file, silently creating a 2 GiB/var/swapbacking file and periodic flash writeback. Overlay2.0.4pinsMechanism=zram. Controlled reboots on.13,.44, and.199proved/var/swapabsent and/sys/block/zram0/backing_devequal tonone;.60still needs that validation after its filesystem recovery. - Overlay
2.0.5initializes the legacy GPSDOPTIONSvariable and reconciles BlueZ's expected configuration-directory mode with Debian's packaged/etc/bluetooth. Live GPSD/BlueZ/PAN restarts on all three reachable nodes produce no corresponding warnings and recover fully. It also overrides Debian lighttpd's request for its optionaltlskernel module: the Raspberry Pi kernel omits kTLS, while HTTPS correctly continues through user-space OpenSSL. A livesystemd-modules-loadrestart completes cleanly on all three. - Overlay
2.0.6bounds sudo's compressed I/O audit history withDefaults maxseq=128. The eight-hour run reproduced a fleet-wide failure in which 409/401/403 unbounded sudo sessions consumed the entire 50 MiB/var/logtmpfs on.13/.44/.199; sudo then rejected every privileged command withENOSPC, although the nodes and role services themselves stayed healthy. After recording the failure, the oldest 288/280/282 ephemeral sessions were removed, leaving the newest 128 and restoring 63--72% free space. The new sequence limit parsed successfully and passed the live security/media HIL checks on every reachable node. The image verifier and HIL suite now assert both the bound and/var/logheadroom. Three concurrent privileged samplers then drove the counters through a natural rollover to sequence 4/4/7 with no failed probe, while/var/logretained 36--39% free even before the closing reboot cleared the old tmpfs sessions. - Burn-in sampling and the HIL suite now inspect the root superblock, current- boot filesystem/media errors, boot command-line shape, and configured versus installed root PARTUUID. This was added after the deeper audit below caught a failure which the ordinary service checks and direct-I/O benchmark did not.
- Burn-in summaries now distinguish overlapping journal observations from
distinct events by journal cursor, retain both historical and current failed-
unit state, and locate the first/last failed probe. A 20-minute companion run
after deployment collected 20/20 good samples per reachable node, zero
filesystem/PARTUUID alerts, zero failed-unit samples, and zero service drops.
It reduced 21 overlapping warning observations to 12 distinct events per node
(four scheduled Comitup scans, three Broadcom messages each), proving the
deduplication works. Memory moved only +0.24/+0.13/-0.07 percentage points on
.13/.44/.199. - The HIL suite now has role-aware Wi-Fi RID and Gutcheck modules. On
.44, all eight Wi-Fi checks pass (AR9271 driver, monitor mode, live packet flow, healthy status, no write errors/restarts, Dronecot2.3.7-1). On.199, all nine Gutcheck checks pass (package0.2.0-1, health/dashboard, enforced API auth, live capability-rich entity fields, zero drops/warnings/restarts, and the four display columns). Other roles skip these modules rather than producing noise.
Active-test evidence¶
- The main run recorded maxima of 52.35 °C, load 3.95, and 14.9% memory used;
there was no throttling or service restart growth. The closing overlay
2.0.6proof collected 77/77 successful samples on each reachable node with clean filesystems/PARTUUIDs, no failed units or service drops, and memory changes of only +0.56/+0.55/+0.32 points on.13/.44/.199. Three historical failed-unit samples came from the deliberately removedrpi-zram-writeback.timerduring the swap-policy migration; every final and post-fix sample had zero failed units. - Concurrent 15-minute CPU/VM stress on all four: no failures, no swap use, no throttling; maximum 52.35 °C.
- Direct-ext4 1 GiB sequential write/read MiB/s:
.1327.7/94.0,.4433.0/94.9,.6048.0/89.0,.19924.6/94.6. No immediate I/O errors occurred during the benchmark, but the later whole-boot audit found pre-existing.60metadata corruption; throughput alone is not a media-integrity test. .60↔.199reached about 936 Mb/s..13and.44advertise gigabit but their link partners advertise only 10baseT; unidirectional transfers reach the full 9.4 Mb/s with zero NIC CRC/symbol errors. Bidirectional loss/retries are consistent with switch buffering between 1 Gb and 10 Mb ports, not AryaOS.- Multicast from
.199does not reach the other three nodes although unicast does. Treat the 10 Mb links and.199multicast isolation as switch/cabling/ IGMP/VLAN work, not image defects. .44received 2,092,896 ambient monitor-mode frames (about 110 frames/s) without capture drops/errors or service restarts..60produced 113 ACARS frames and tracked five aircraft before its repair reboot, with zero gateway write errors. Gutcheck processed 1,407 live events with zero drops, warnings, or restarts. No live DJI target was present for.13, but the AntSDR feed and Dronecot service remained established with zero write errors/restarts.- The clean pre-intervention install-media baseline was 2.19--3.00 MiB/hour; an early post-overlay interval including once-per-minute audit probes was 5.55--7.03 MiB/hour. The later 4.66-hour interval averaged 73.7--75.2 MiB/hour because it deliberately included package installs, repeated HIL/apt checks, Docker image/container recovery work, and hundreds of sudo rollover sessions; it is not an idle-write baseline.
- After the closing controlled reboot,
.13,.44, and.199returned with new boot IDs. All default HIL suites passed, as did.13's UAS profile with all eight AntSDR checks,.44's eight Wi-Fi RID checks, and.199's nine Gutcheck API/capability/UI checks. Exact fresh-boot scans found zero kTLS module, GPSDOPTIONS, BlueZ configuration-directory, filesystem/media, sudoENOSPC, or USB-reset regressions. Packages and dependencies audited clean; root PARTUUIDs matched; swap was RAM-only with no backing device or/var/swap; and no systemd unit failed. A forced 300-session sudo test on each node retained exactly 128 sessions (16.4 MiB) and left/var/logonly 33% used.
Source and image validation¶
- Final local gates on branch
fix/dronecot-ws-recoverypassed: AryaOS Python tests 69 passed/3 skipped, Gutcheck 110 passed, Ansible syntax, CI-equivalent shellcheck, strict MkDocs rendering, YAML parsing, andgit diff --check. - The first workflow dispatch, Actions run
30759152511, exposed a CI-only filename bug: the raw reffix/dronecot-ws-recoverybecame part of pi-gen's image name, so/was interpreted as a directory separator during export. Commit20bb47asanitizes only the filesystem-facing image name toaryaos-fix-dronecot-ws-recovery-devwhile preserving the original ref in the image provenance stamp. A second run exported and uploaded the image, proving that fix. - The second run (
30759601742) was then correctly blocked by the image verifier because the signed package repository still served Dronecot2.3.4-1while AryaOS requires>=2.3.7. Packages workflow run30760437018refreshed the repository from the already-published Dronecotv2.3.7release; the public arm64 apt index now serves2.3.7-1. - Final Actions run
30760485704at commit20bb47apassed in 21m37s. The image verifier reported 258 ok, 0 failed, including Dronecot2.3.7-1; image and SBOM artifacts, image hashes, overlay deb, and the prerelease were all published asv2026.08.02.182711-20bb47af0ffe-dev. - The definitive Actions run
30761773782then built the exact documented head20a77fbin 26m32s. Its verifier reported 259 ok, 0 failed, including the new ACARS role-management assertion and Dronecot2.3.7-1. The image, SPDX and CycloneDX SBOMs, hashes, overlay2.0.7deb, and prerelease were published asv2026.08.02.190609-20a77fb8dbb2-dev.
.60 install-media incident and reflash recovery¶
- The deeper kernel/superblock audit found ext4 directory-checksum failures in
/usr/src/linux-headers-6.18.39+rpt-common-rpi/include/netand/srv. The root superblock wasclean with errors; the boot FAT was dirty. No contemporaneous MMC I/O error was logged, so the evidence establishes damaged install media, not a specific hardware root cause. /boot/firmware/cmdline.txtitself contained corrupt random-looking data and named no usable root. Before reboot it was reconstructed as a single line with the current root PARTUUID (7c6f9611-02),fsck.repair=yes, and a one-bootfsck.mode=force. Redacted configuration and support archives were copied off-host into the burn-in evidence directory before intervention..60had not returned by the final 17:11 UTC ping/SSH/mDNS/ARP check after the 11:47 UTC repair reboot. It later returned with new host keys, hostnamearyaos-ff84, and a new machine ID, establishing that it was reflashed rather than resuming the damagedaryaos-fad2installation.- The fresh image was healthy at the filesystem layer (clean root superblock,
matching root PARTUUID, and no current-boot filesystem/media errors), but was
still on overlay
2.0.0. It also had Trixie's file-backed swap loop and had misclassified the LimeSDR as AIS, leavingais-catcherfailed. Overlay2.0.7and the signed ACARS stack were installed, and the capability was set explicitly toacars. - That transition exposed and fixed a source bug:
aryaos-roleknew that theacarscapability maps toacarsdec acarscot, but omitted both units fromall_managed_units, so it could persist the label without enabling the services. Commit9c9782cadds both units, a regression test, and an image verifier assertion. - After a controlled reboot,
.60had only RAM-backed zram (no backing device and no/var/swap), no failed units, and passed the complete default HIL suite. LimeSDR Mini v2 serial1DBB4189078E3Fopened over USB 3.0; bothacarsdecandacarscotwere enabled/active. The decoder emitted a 384-byte JSON datagram to the gateway on loopback at 19:42:34 BST with zero capture drops, proving live RF-to-gateway data flow. One initial USB 2.0 open attempt failed during boot enumeration; the bounded service restart succeeded 20 seconds later over USB 3.0 and remained error-free. - ACARSCOT was subsequently enrolled directly to the operator-supplied TAK
server (credentials deliberately omitted). PyTAK resolved the enrollment URL
to WSS on port 8443; the socket remained established with both WebSocket
workers running and zero ACARSCOT warnings or restarts. The three enrollment
cache files are mode
0600under/var/lib/acarscot, backed by a localStateDirectory=acarscotservice drop-in so a reboot does not consume the enrollment token again. A forced service restart preserved the cache byte-for-byte and reconnected successfully. A controlled reboot then changed the boot ID while preserving the same cache digest; ACARSCOT automatically re-established WSS with no warnings or restarts. The complete default HIL suite passed again on that boot (including 23 security and three storage checks). A 45-second follow-up RF capture was quiet, which is normal for sparse ACARS traffic; the earlier live 384-byte decoder datagram remains the data-path proof.
2026-07-19 to 21 sweep - HIL hardening + landing-page features (SHIPPED)¶
Two arcs, both merged and in a green image: v2026.07.21.211313-4e5923568c11-dev
(verify-image: 135 ok, 0 failed). User is flashing it now for HIL testing -
resume by testing this release on the box.
Arc 1 - HIL security hardening (radios / EMCON / isolation)¶
Hardware-in-the-loop pentest of the appliance. Landed (aryaos, all asserted in
verify-image.sh):
- Wi-Fi/AP isolation: public.xml dropped <forward/> so the onboarding AP/PAN
can't gateway to wired ethernet; new aryaos-hotspot firewalld zone withholds
ssh/node-red/mesh from onboarding clients; NM owns the zone via connection.zone
(comitup-callback.sh uses nmcli connection modify ... + device reapply, NOT
firewall-cmd --change-interface, which NM reverts). pan0 statically bound.
- EMCON / radio silence (aryaos-radio): ap {on|off}, silence {on|off} does
nmcli radio wifi off + rfkill block wifi bluetooth; --boot re-applies from
/etc/aryaos/emcon flag; comitup/bt-pan/bt-ready gated off via
ConditionPathExists=!/etc/aryaos/emcon drop-ins. Ethernet + SDR RX unaffected.
- Node-RED unauth-root closed: drop-in runs it User=node-red (was root); default
publicly-known password (aryaos415) rotated on first boot; cockpit-aryaos card to reset.
- XXE/billion-laughs guards + systemd sandboxing on aryaos-neighbord (score reduced from 9 to 3),
socket 0600; TAK data-package import moved off CGI to a root CLI over an AF_UNIX
socket with SSRF host-blocking. Zeroize stays best-effort sanitize (usable box), NOT
scorched-earth. SSH password auth intentionally STAYS ON (don't lock users out).
- chrony NTP server (local stratum 10, gpsd SHM refclock, allow) served on the LAN zone.
Arc 2 - landing-page features + style fix (cockpit-aryaos v1.5.0 + plugin patches)¶
- Unstyled plugins fixed: React/esbuild plugins bundle SCSS to
dist/index.cssbutindex.htmlnever linked it > completely unstyled in Cockpit. Added<link rel="stylesheet" href="index.css">+ sharedbranding.css(matching cockpit-gps/aiscatcher) to cockpit-cotbridge/adsbcot/dronecot/aiscot/sdrconnect. - Landing-page location chip (cockpit-aryaos): offline North America base map +
live position. Geometry ships in
aryaos-basemap.js(window.ARYAOS_BASEMAP, public-domain Natural Earth 110m, ~29KB) rendered client-side as SVG with a Web-Mercator projection so the marker aligns; no tiles fetched (works in EMCON). Position fromgpspipe --jsonbest 2D/3D TPV, falls back to configSTATIC_LAT/LON. NA-only by design (primary sales region); off-map positions are labelled, not mis-plotted. - Also this batch: OS image backup card (
aryaos-image-downloadpulls the box's own.img.xz), NTP time-server exposure, bundled cloudtak removed.
Build/release gotchas learned this sweep (IMPORTANT)¶
- image-commit stamp: pi-gen runs inside a Docker container (
usimd/pi-gen-action).GITHUB_ENVvars do NOT cross into it -ARYAOS_BUILD_SHAmust be passed viadocker-opts: -e(fixed #164). A prior "fix" using GITHUB_ENV silently left the stampunknownand failed the gate. Same rule for any new build-time env a stage needs. - Plugin debs publish on TAGS ONLY (
build.ymlsteps areif: startsWith(github.ref, 'refs/tags/')). Merging a plugin PR tomainonly runs validation - it does NOT produce a new deb. To ship a plugin change: push avX.Y.Zgit tag (git push, notgh release create- the workflow triggers onpush: tags, not thereleaseevent) > build.yml packages the deb + creates the release > then publish the apt repo. - apt repo path is
https://snstac.github.io/packages/apt(note the/aptsubpath), suitestable, componentmain, index at.../apt/dists/stable/main/binary-arm64/Packages. Ingest new debs by dispatchingsnstac/packagespublish.yml(gh workflow run publish.yml --repo snstac/packages; also runs daily 06:17 UTC) - it pulls each product's latest GitHub Release assets. THEN rebuild the aryaos image so apt pulls the new versions. - Correct order to land a plugin change in an image: merge PR > tag release > publish.yml >
image build. Skipping any step ships the old deb (and
verify-imagenow catches the cockpit-aryaos case:card-location+aryaos-basemap.js).
This sweep's plugin releases: cockpit-aryaos v1.5.0, cockpit-cotbridge v1.2.1, cockpit-aiscot v1.2.2, cockpit-dronecot v1.1.2, cockpit-adsbcot v1.2.2. (cockpit-sdrconnect CSS fix merged but unreleased - not in the image manifest / apt index.)
2026-07-15/17 sweep - "never SSH" + fleet dedup (SHIPPED)¶
Full review + implementation sweep. All 11 PRs merged and released (2026-07-17, in dependency order: packages > aryaos > cockpit-aryaos > plugins). What landed:
- aryaos overlay helpers (all driven by cockpit-aryaos cards, no SSH):
aryaos-support-bundle(redacted diagnostics tarball,/var/lib/aryaos/support/),aryaos-set-nodered-password(rotates the publicly-known default and setssettings.jstoroot:node-red 0640),aryaos-sdr(RTL-SDR enumerate + EEPROM re-serial; this added thertl-sdrpackage - onlylibrtlsdr0shipped before),aryaos-role(runtime device roles multi/air/maritime/cuas/relay; CoT core cotbridge/lincot/ gpscot/gpsd never touched; ADS-B decoder followsARYAOS_ADSB_DECODER). Installed via overlay deb + chroot stage + Ansible; asserted inverify-image.sh; all four now in the CI shellcheck list (they have no.shsuffix - the globs missed them, don't re-break that). - SBOMs -
scripts/generate-sbom.sh+ pinned syft, every image build emits SPDX + CycloneDX attached to the release. The step runs before the tag push on purpose (an SBOM failure must not strand a tag). CAUTION: it runs syft undersudo, so it chownsdeploy/back to the runner afterward - a prior version stranded a tag by leavingdeploy/root-owned (fixed in #131). - cockpit-aryaos v1.3.0 - six new cards: support bundle, Node-RED password, Radios (RTL-SDR), Device role, comitup hotspot password, Tailscale join. The four helper-backed cards need aryaos-overlay ≥ the 2026-07 helpers; on older images they show a clear error toast.
- cockpit-cotbridge v1.2.0 - React/TS rewrite + structured lane editor.
src/cotUrl.tsis a differentially-tested port ofcotbridge/src/cotbridge/config.py - keep the two in sync if lane/URL validation changes.
- gdlcot (new repo, v1.0.0) - CoT > GDL90 UDP broadcast so ForeFlight/EFBs display the TAK air picture. In the sensor manifest + air/multi roles; egress-only (no inbound firewall service). 48 tests incl. the GDL90-spec CRC known-answer.
- @snstac/cockpit-shared (new repo, v1.1.0) - shared
serviceCard/tlsCard/envDefaultFile/types. Source-shipping model: consumers depend ongithub:snstac/cockpit-shared#vX.Y.Zand esbuild bundles the.ts/.tsxdirectly (no npm registry, no build step);cockpitresolves from each consumer'spkg/lib. Keylessnpm civerified (pacote fetches public repos over anonymous https even though the lockfileresolvedsaysgit+ssh). All five family-B plugins consume it (aiscot v1.2.1, adsbcot v1.2.1, dronecot v1.1.1, lincot v1.1.1, cotbridge v1.2.0). Bumping the shared package = bump its tag, then bump the#vX.Y.Zref in each consumer. - README amd64 claim softened (arm64 today, amd64 planned) - tracking #129 (installer-script path first: the apt repo + overlay deb already run on any Debian host).
Issue tracker triaged 42 > 11 open (each closure commented with what superseded it).
Next hardware session: flash the milestone image below and exercise all six
cockpit-aryaos cards + verify the Cockpit expired-password first-login flow (the
prerequisite for a first-login wizard); good 09-security.sh test candidates. Then:
amd64 installer (#129), unified COP map, track record/replay (#8/#9), and the cockpit
plugins still on vanilla-JS could adopt cockpit-shared patterns.
Current known-good build¶
- Latest successful dev image:
v2026.07.17.165541-5fa79a7bfae5-dev- the milestone build: first image with gdlcot, the four field-support helpers, device roles, and working SBOM attachment. - Release: https://github.com/snstac/aryaos/releases/tag/v2026.07.17.165541-5fa79a7bfae5-dev
- Assets verified present:
image_*.img.xz,aryaos-overlay_2.1_all.deb,*.spdx.json,*.cdx.json. - Notes: dev/lab image (
aryaos-dev-labSSH key, passwordlesspisudo, no first-boot password expiry). Do not field it. For a release image, dispatch the Pi-gen workflow with thereleaseinput checked. - Watch: the apt index refreshes on the packages repo's daily/push publish - the new plugin deb versions (cockpit-aryaos 1.3.0 etc.) reach deployed units via one-click updates once that runs.
Recent build blockers fixed:
sikw00fcot.servicewas missing AryaOS site config inheritance. Root cause was a brokensedexpression instage-cotbridgethat used/as the delimiter while matching/etc/default/<svc>. Fixed in81ca548with a path-safeawkinsert. Keep siteEnvironmentFile=/etc/aryaos/aryaos-config.txtbefore the service-specific/etc/default/<svc>line.- GitHub release publishing failed on immutable releases because
softprops/action-gh-releasepublished the prerelease before uploading the image asset. Fixed inabe8e41by usinggh release create, which creates a draft, uploads assets, then publishes. sikw00fcotdepends onpython3-pymavlink; that package is now published from https://github.com/snstac/python3-pymavlink and indexed by https://snstac.github.io/packages.
The big picture¶
AryaOS is the master consumer of the PyTAK stack. Three pillars landed in June 2026:
- Everything installs from the signed apt repo - https://snstac.github.io/packages,
built by snstac/packages from each product's
latest GitHub release (repos listed in its
products.txt). No vendored sensor binaries remain in this repo; the only vendored artifacts are trust anchors (shared_files/aryaos/snstac-packages/, FlightAware repo deb). - Cockpit is the single admin surface - nine standalone
cockpit-*plugin repos/debs (adsbcot, aiscot, aiscatcher, dronecot, lincot, gps, cotbridge, gpscot, aryaos).cockpit-aryaos("AryaOS Site") manages the site-wide layer:/etc/aryaos/aryaos-config.txt(siteCOT_URLetc.) and one-shot TAK TLS cert upload to/etc/aryaos/tls(key0640 root:tak-certs; group reconciled byaryaos-firstboot.shevery boot). Per-tool plugins edit/etc/default/<svc>. - CI builds dev images by default - every push to
mainproduces av<ts>-<sha>-devprerelease with lab access baked (dev SSH key, pi NOPASSWD, no password expiry) for burn-and-test. Hardened release images require dispatching the Pi-gen workflow with thereleaseinput checked.scripts/verify-image.shloop-mounts every built image and asserts ~58 facts (packages, units, files, and the lab/release security contract) before anything publishes.
Architecture invariants (don't break these)¶
- Site-config inheritance: every gateway unit loads
EnvironmentFile=-/etc/aryaos/aryaos-config.txtbefore its own/etc/default/<svc>- site sets defaults, per-service values override. The injection happens in each stage's chroot script (sed after[Service]); drop-in files would invert the precedence (drop-ins parse after the unit file). - CoT routing hub:
adsbcot,aiscot,dronecot,lincot, and other local PyTAK feeders should keepCOT_URL=udp+wo://127.0.0.1:28087. COTBridge listens onudp+ro://127.0.0.1:28087and owns the external egress lanes: default Mesh SAudp+wo://239.2.3.1:6969, optional TAK Server, and other tools. Do not point each feeder independently at the same TAK Server except for deliberate legacy/debug bypass. - apt pinning:
install-sensor-debs.shpinsrelease o=snstacat 995 because stage-adsbcot pins trixie at 990 and Debian ships an SDR-less readsb that must never win. readsb is alsoapt-mark hold(statushold ok installed- verify-image accepts both hold and install). - Exactly one
EXPORT_IMAGEstage, last in everySTAGE_LIST(PR validation enforces).ARYAOS_CI_TRIM_WORK=1(CI only) deletes stale stage rootfs trees - pi-gen full-copies per stage and 72 GB arm64 runners can't hold ~15 copies (the fleet has 72 GB and 145 GB VMs; never rely on runner luck).increase-runner-disk-sizeis broken on arm64 runners - keep it false. - Release publication on immutable-release repos: use
gh release createfor releases with image assets. Do not go back tosoftprops/action-gh-releaseunless it is configured to keep the release draft until after asset upload.
Bluetooth PAN¶
AryaOS now includes a local-only Bluetooth PAN/NAP service for phone-to-box IP
connectivity without network egress. The service is aryaos-bt-pan.service; helper
source is shared_files/bt-pan/aryaos-bt-pan-nap; docs are in
bluetooth-pan.md.
Defaults in /etc/aryaos/aryaos-config.txt:
BT_PAN_ENABLED=1
BT_PAN_BRIDGE=pan0
BT_PAN_ADDRESS=10.44.0.1
BT_PAN_PREFIX=24
BT_PAN_DHCP_START=10.44.0.20
BT_PAN_DHCP_END=10.44.0.60
BT_PAN_DHCP_LEASE=12h
Expected behavior:
- AryaOS registers a BlueZ Network Access Point on
hci0and createspan0. - Paired phones get a DHCP lease on
10.44.0.0/24; AryaOS is10.44.0.1. - No NAT or forwarding is enabled. This is only for reaching AryaOS local services,
for example
https://10.44.0.1:9090/. - Phone OS support varies. Android vendor builds differ; iOS is usually restrictive for arbitrary Bluetooth PAN client use.
Hardening + one-click updates (new, 2026-07-02)¶
See security.md for the full posture. Summary of what landed:
- firewalld enabled with an explicit allowlist in the default zone
(
shared_files/aryaos/firewalld/); AntSDR link pinned to the trusted zone viazone=trustedinaryaos-antsdr.nmconnection. Operators use Cockpit > Networking > Firewall. If a new service opens a port, add a firewalld service XML + zone entry + verify-image assert, or it will be unreachable. - fail2ban (sshd jail), sshd drop-in (
50-aryaos.conf, password auth deliberately stays on), sysctl hardening, unattended-upgrades (Debian security only; snstac origin commented out by design). - Per-device web TLS:
aryaos-firstboot.shregenerates the snakeoil key and/etc/lighttpd/ssl/snakeoil-combined.pemonce per device (marker/etc/aryaos/.web-tls-regenerated). Firstboot also stoppedchown -R node-red /etc/aryaos- Node-RED now owns only the config file, and/etc/aryaos/tlsisroot:tak-certs 0750with the key0640. - One-click updates:
/usr/local/sbin/aryaos-update {check|apply|status} aryaos-update.service(oneshot, survives browser close), driven by the Software updates card in cockpit-aryaos ≥ 1.1 (falls back tosystemd-run+ plain apt on pre-2.1 images). JSON state in/var/lib/aryaos/update-*.json.- aryaos-overlay 2.1 is built by CI and attached to releases as a deb
asset, so units can upgrade the overlay itself once
snstac/aryaosis in the packages repoproducts.txt(see open items - sequencing matters). - New verify-image asserts cover all of the above; runtime checks are in
scripts/aryaos-test/tests/09-security.sh.
GPSCOT (new, 2026-06-12)¶
gpscot package > /usr/bin/gpscot: feeds onboard GNSS to TAK
devices per https://ampledata.org/network_gps.html - CoT position events to COT_URL
(default udp+broadcast://255.255.255.255:4349, ATAK's External or Network GPS) and
raw-NMEA passthrough for WinTAK (NMEA_TARGETS). Reads gpsd's JSON socket; pytak for
transport (so PYTAK_TLS_* applies). Ships disabled; managed in Cockpit > GPSCOT
(cockpit-gpscot). Verified live on the dev
Pi. Source and Debian/RPM release packaging live in https://github.com/snstac/gpscot.
Fleet state (all on pytak >= 7.3.0, releasing versioned debs)¶
| Repo | Release | Notes |
|---|---|---|
| pytak | 7.3.11 | capability line: cert enrollment, tak://, wss://, marti://, pytak dp, +wo/+ro, MQTT |
| adsbcot 9.1.0, aprscot 8.0.0, inrcot 5.2.1, cotproxy 1.0.1 | Jun 2026 | pipelines modernized (lincot-style ci.yml) |
| aiscot 7.1.4, dronecot 2.1.3, djicot 1.2.0, lincot 1.2.3, cotbridge 0.1.13, sikw00fcot 1.0.0 | Jun 2026 | cotbridge ≥ 0.1.13 no longer ships its cockpit plugin in-deb; sikw00fcot is SiKW00F MAVLink fan-out to CoT |
| python3-pymavlink | 2.4.49-1 | packaged for AryaOS so sikw00fcot can install cleanly; pure-Python fallback path, depends on python3 and python3-lxml |
| readsb | 3.16.15-2 | synced to wiedehopf dev; build debs in debian:trixie containers because Ubuntu builds depend on librtlsdr2, uninstallable on Debian |
| AIS-catcher fork | 0.68 | release workflow runs upstream build-debian.sh as root; upstream CI workflows disabled on the fork |
| windtak 1.0.0, takline 0.1.1 | Jun 2026 | |
| cockpit-* x9 | 1.0.0+ | Cockpit plugins use the dark AryaOS/GPSCOT visual style; watch for regressions to white-on-white UI |
LINCOT / Host Beacon¶
AryaOS expects LINCOT v1.3.1+ for dynamic host remarks and gpsd-derived CoT accuracy.
/etc/default/lincot sets GPS_INFO_CMD="gpspipe --json -n 5" and
REMARKS_EXTRA_CMD=/usr/local/sbin/aryaos-lincot-remarks. The helper emits CPU/load,
RAM, swap, disk, temperature, uptime, and Pi throttle state. LINCOT maps gpsd TPV
altHAE/eph/epx/epy/epv to CoT hae/ce/le.
AryaOS also sets COT_DETAIL_XML_CMD=/usr/local/sbin/aryaos-cot-detail so the LINCOT
host beacon carries a structured <__aryaos> detail block. aryaos-neighbord.service
listens on Mesh SA multicast (239.2.3.1:6969) and writes /run/aryaos/neighbors.json
for /cgi-bin/aryaos-neighbors and the landing-page neighbor table.
Recurring gotchas (each cost a build this month)¶
gh release uploadfails on fresh tags -gh release view || gh release createfirst.- Immutable GitHub releases reject assets uploaded after publication. Use
gh release create <tag> <asset> ..., not a create-then-upload flow that publishes first. dpkg-deb -c | grep | head> SIGPIPE kills dpkg-deb underset -e.dh_installtreats destinations as directories (foo.confbecomes a dir).- stdeb deb names default to
python3-<name>withoutstdeb.cfgPackage3:. - A single private/release-less repo in
products.txtkills the whole publish ("release not found"); publishes racing a just-pushed tag fail the same way. - This repo has
core.fileMode=false-git update-index --chmod=+xfor scripts. - GitHub GraphQL intermittently 401s here; use REST (
gh api) with retries.
Dev lab¶
Known lab hosts recently used:
- The retired fixed-address development target may be unreachable on current
lab networks; use
scripts/aryaos-dev-deviceor an explicit current address. 192.168.0.199: ADS-B box used for readsb/adsbcot/gpsd/dashboard checks.192.168.0.13: UAS-mode box with AntSDR and BlueMark DroneScout bridge DS100.
Use the lab SSH key in shared_files/aryaos/ssh/ where possible. Integration suite:
After flashing the latest dev image, first checks should include:
systemctl status cotbridge lincot adsbcot aiscot dronecot sikw00fcot/cgi-bin/aryaos-portal-statusand/admin/aryaosgpsddata on GPS-capable unitsreadsband/run/adsb/aircraft.jsonon ADS-B units- AntSDR Ethernet reachability and dronecot feed behavior on UAS units
- Bluetooth pairing plus
aryaos-bt-pan.service/pan0on Bluetooth-capable units
Open items / next handoff tasks¶
- Hardening burn-in (2026-07-02): flash the first post-hardening dev
image and run the integration suite (esp.
09-security.sh). Watch for firewalld regressions: comitup hotspot onboarding, Bluetooth PAN DHCP, Mesh SA neighbor discovery, AntSDR > dronecot, Docker-published CloudTAK ports, Node-RED/AIS-catcher dashboards. Then, after the first release with thearyaos-overlay_*_all.debasset exists, addsnstac/aryaosto packagesproducts.txt(adding it earlier breaks the whole publish -gh release downloadfails on a release with no deb assets). - Flash and test the latest dev image: burn
v2026.06.23.212757-abe8e41bf5e2-dev, then run the integration suite against the current lab ADS-B and UAS boxes. Pay special attention tosikw00fcot, COTBridge inheritance, and the new Bluetooth PAN service. - Bluetooth PAN live validation: pair an Android phone to AryaOS, confirm it
receives
10.44.0.20-60, confirmhttps://10.44.0.1:9090/works, and confirm no unwanted NAT/default-route behavior is introduced. - AntSDR operational follow-through: keep the AntSDR path focused on
alphafox02/antsdr_dji_droneid; do not rely on DroneScout containers for this setup. Verify the matching Ethernet interface comes up and that dronecot consumes the AntSDR output. - Release hygiene: for dev builds, verify published prereleases have the image asset attached. Delete empty prereleases immediately if publish fails after tag creation.
- takline + windtak are private - the packages publish token can't read them;
flip public (
gh repo edit snstac/<r> --visibility public --accept-visibility-change-consequences), then add toproducts.txt. - Archive
spotcot(pre-pytak-5, dormant since 2022) andcockpit-sdrconnect(unmodified cockpit-dronecot clone, no releases). - Delete stray fork
snstac/AIS-catcher-1(accidental duplicate). - adsbcot PyPI job needs a trusted publisher configured on PyPI (release works regardless; the job just reads red).
- Possible next plugins: cotbridge lane editor (structured
cotbridge.iniUI - current plugin is a raw editor), windtak/aprscot pages; backport SIGPIPE fixes everywheredpkg-deb -c | headsurvives. - Node-RED runtime check after the worldmap 5.x / tfr2cot 2.0 major bumps (palette installs now go through the npm 11 override).