Commit Graph

64 Commits

Author SHA1 Message Date
68e2723747 fix(webext): tag-pinned .xpi release URL + make_latest:false (ref #532)
Publishing webext-v* with the default make_latest would steal the
"latest" release pointer from the Android APK release, breaking the
APK endpoint's /releases/latest/download/secubox-toolbox-android.apk
fallback. Publish the webext release with make_latest:false and point
the /wg/toolbox.xpi endpoint + fetch helper at the tag-pinned download
URL instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:45:40 +02:00
b2ee2a97ef fix(webext): clean web-ext lint — drop unused optional_host_permissions, ignore build.sh/README (ref #532)
web-ext lint: 0 errors, 2 benign warnings (AMO data-collection
declaration is submission-time, tied to the signing follow-up;
service_worker-ignored is the intentional cross-browser pattern).
optional_host_permissions needed FF128 and was unused at MVP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:21:45 +02:00
c77e6250a9 feat(webext): browser extension — emancipate R3 cartographie live (ref #532)
New client clients/webext-toolbox/ (WebExtension MV3, Firefox .xpi +
Chromium): surfaces the toolbox live tracker analysis in the browser.

- manifest.json MV3, cross-browser background (service_worker + scripts
  for Firefox 115+ event page); host_permissions *.secubox.in only
- api.js: shared client over /wg/r3-check, /social/me (pair → HMAC token),
  /social/graph/{token}, /social/wipe/{token}
- background.js: toolbar badge = live tracker count, silent re-pair on
  token expiry, colour escalates gold → anti-bot → operator-grade
- popup: 4 stat tiles + dependency-free mini Round-Eye SVG graph + top
  trackers tagged CDN/anti-bot/operator-grade + cartographie/PDF/RGPD-wipe
- options: host / analysis window / manual token
- build.sh + build-webext.yml (web-ext lint + build, release on webext-v*)

Serve from the toolbox (2.6.14):
- GET /wg/toolbox.xpi (local file, else 302 → latest release asset)
- '🧩 Extension navigateur' button on both onboard panels
- sbin/secubox-toolbox-fetch-xpi + postinst serve dir + rules install

No server-side CORS needed (MV3 host_permissions). MVP polls /social/graph
and computes the delta client-side; SSE /social/live is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:08:06 +02:00
cf3aef48c8 feat(toolbox): serve Android APK from /wg/toolbox.apk + onboard button (#536)
Follow-up to #531 — one-tap APK install from the cabine.
  - api.py GET /wg/toolbox.apk: serve local APK (android content-type),
    302 → latest GitHub release asset if absent (never dead-ends).
  - /wg/onboard Android panels (inline + _install_panels): 📱 Installer
    l'app ToolBoX (1-tap) button.
  - sbin/secubox-toolbox-fetch-apk: pull latest release asset into the
    serve path (best-effort + APK magic check); postinst creates the dir
    + first fetch.
  - build-android-apk.yml: publish APK as release asset
    secubox-toolbox-android.apk on android-v* tags (contents:write).
  - changelog 2.6.13.

Live on gk2: /wg/toolbox.apk 302 → release (fallback, no release yet),
serve dir created, onboard button rendered.
2026-06-12 23:46:29 +02:00
ab67c981dd feat(android): scaffold one-tap toolbox R3 installer + CI (ref #531)
Kotlin/Jetpack-Compose app under clients/android-toolbox/ replacing the
manual Android onboarding tutorial. 5-step flow:
  discover -> install CA (KeyChain intent) -> import WG profile (handed
  to the WireGuard app via FileProvider) -> verify (/wg/r3-check) ->
  live cartographie sociale (/social/me).

  - ToolboxApi: plain HttpURLConnection client for /wg/ca.crt,
    /wg/profile/new, /wg/r3-check, /social/me (no Retrofit/OkHttp —
    minimal deps + CI).
  - MainActivity: Compose stepper UI, palette-matched (cosmos/gold/cyan),
    FR copy. Intents for CA install + WireGuard handoff + Play fallback.
  - Gradle (AGP 8.5.2 / Kotlin 1.9.24 / Compose BOM 2024.06), minSdk 26,
    targetSdk 34, package in.secubox.toolbox. No wrapper jar committed.
  - res: adaptive launcher icon (vector eye glyph), theme, file_paths,
    strings — all text/XML, no binaries.
  - .github/workflows/build-android-apk.yml: setup-android + setup-gradle
    8.9 build assembleDebug -> APK artifact (sideloadable).
  - README documents the flow, build, and the Android user-CA-trust
    constraint (MVP guides manual confirm; release signing is follow-up).

Closes the scaffold half of #531; CI produces the debug APK.
2026-06-12 18:15:46 +02:00
3d52b63d26 ci: drop espressobin-v7 + espressobin-ultra from scheduled image matrix (ref #503)
The two boards fail in the cross-arm64 chroot stage of build-image.yml
and (even with fail-fast: false) block the downstream release.yml job
from publishing the OTHER boards' images.  Releases v2.13.9 through
v2.13.12 all hit this trap.

This change keeps both entries available via workflow_dispatch (operators
can still build them on-demand), but removes them from the push-tag
scheduled matrix so mochabin / vm-x64 / rpi400 actually ship on tag.

Board support files (board/espressobin-*/, image/build-image.sh
--board espressobin-*) stay in tree.

  - build-image.yml matrix excludes espressobin-v7 + espressobin-ultra
    on push and workflow_call.
  - build-image.yml workflow_dispatch choice list keeps both entries
    flagged as on-demand only.
  - Release notes template drops the two image rows, adds a note
    explaining the on-demand path.
  - Install instruction adjusted (MOCHAbin + Raspberry Pi 400).
2026-06-09 09:42:08 +02:00
4341da96a0 fix(ci): collect+upload kernel .deb on failure (linux-image often built before headers fail)
The bindeb-pkg target builds linux-image-*.deb FIRST then attempts the
linux-headers-*.deb. The headers build can fail (silent in CI log) while
linux-image is already on disk and ready to deploy. The deployment-
critical artifact for the MochaBin mesh integration is linux-image —
headers/libc-dev are needed only for out-of-tree module builds against
this kernel (which we don't do today).

Add `if: always()` to both Collect and Upload steps so partial
artifacts survive a late bindeb-pkg failure. Downgrade if-no-files-found
from `error` to `warn` so a fully empty /tmp/artifacts/ doesn't mask
the real upstream failure with a misleading artifact error.
2026-06-02 14:17:22 +02:00
6eb399eade fix(ci): heredoc → loop for arm64 ports.list (YAML parser couldn't handle col-0 EOF)
Previous attempt used a heredoc with EOF marker at column 0, which
YAML parses as a new top-level key, breaking the workflow file.
Replace with the same loop pattern used elsewhere in the step
(echo | tee -a with iteration over codename suites).
2026-06-02 13:29:37 +02:00
c37368de7a fix(ci): point arm64 apt sources to ports.ubuntu.com (security/archive serve amd64 only)
Ubuntu's security.ubuntu.com and archive.ubuntu.com host amd64/i386
only. arm64 packages live on ports.ubuntu.com.

After `dpkg --add-architecture arm64` + `apt-get update`, the runner
404s on:
  https://security.ubuntu.com/ubuntu/dists/noble/main/binary-arm64/Packages

Fix: pin existing entries to [arch=amd64] and add [arch=arm64] entries
pointing to http://ports.ubuntu.com/ubuntu-ports/. Detected codename
via /etc/os-release so the workflow stays compatible across runner
updates (jammy/noble/numbat).

Unblocks libssl-dev:arm64 install for cross-arm64 kernel .deb build.
2026-06-02 13:26:23 +02:00
e17f757931 fix(ci): enable arm64 multi-arch + install libssl-dev:arm64 in build-kernel.yml
dpkg-buildpackage -aarm64 (cross-build) resolves Build-Depends to the
target arch. The kernel package's debian/control declares
`Build-Depends: libssl-dev` without arch suffix, so dpkg-checkbuilddeps
looks for libssl-dev:arm64 and fails when only libssl-dev (amd64) is
installed.

Add `dpkg --add-architecture arm64` before `apt-get update` so the
arm64 package index is available, then install libssl-dev:arm64
alongside the host libssl-dev.

This is a pre-existing CI gap, exposed by run 26816056566. Unrelated
to the secubox-mesh fragment (signed-regdb was a red herring).
2026-06-02 13:24:20 +02:00
67c54ee421 feat(kernel): add 802.11s mesh stack (mt76x2u/ath10k_pci/ath9k_htc) — CM-MESH-MPCIE-2026-06 v0.2.1
Append WIRELESS/WIFI block to OpenWrt-merged kernel fragment so the next
build-kernel.yml run ships:
  - mac80211 + 802.11s mesh + HWMP (=m)
  - ath10k_pci for QCA9880 / WLE900VX backhaul mesh
  - mt76x2u for MT7632U USB access client
  - ath9k_htc for AR9271 firmware-free audit dongle
  - signed regulatory DB (FR domain lock via secubox-mesh postinst)

Add four sanity-check greps in build-kernel.yml so a future fragment
regression fails the CI before producing a kernel .deb without WiFi.

Manual workflow_dispatch of build-kernel.yml required to materialise
the new linux-image-*.deb (artifact path not yet wired into
build-image.yml — see tracking issue).
2026-06-02 12:59:55 +02:00
8dc43ca6f9 fix(ci): install binutils-aarch64-linux-gnu for arm64 build-packages (ref #431)
After #427 added '-a matrix.arch' to dpkg-buildpackage, debhelper now
correctly invokes the cross-toolchain binaries:

  - aarch64-linux-gnu-strip  (used by dh_strip)
  - aarch64-linux-gnu-objdump (used by dh_makeshlibs)

…which were not installed on the amd64 CI runner. Result: arm64 builds
of arch-specific packages shipping prebuilt arm64 ELF binaries failed:

  - secubox-sentinelle-gsm — dh_strip on bin/secubox-redsea
  - secubox-daemon         — dh_makeshlibs on secuboxctl

Install binutils-aarch64-linux-gnu (~5 MB) only when matrix.arch == arm64.
Folded into the existing apt step to keep one network round-trip.

Single workflow change > per-package debian/rules no-op overrides:
- no need to revisit every future arch-specific package
- preserves real strip benefit (smaller .deb)
- fixes the CI gap at the source

This is the final piece behind #427 + #425 to unblock APT publish on
arm64 since v2.13.0.
2026-05-30 14:38:04 +02:00
cd177020e5 fix(ci): pass -a \${{ matrix.arch }} to dpkg-buildpackage (closes #427)
build-packages.yml ran `dpkg-buildpackage -us -uc -b` without -a, so on the
amd64 ubuntu-latest runner the arm64 matrix slot defaulted to amd64. For
Architecture-specific packages (notably secubox-sentinelle-gsm =
Architecture: arm64) that means no binary is produced and dpkg-genbuildinfo
fails with "binary build with no binary artifacts found" → that job has
been red since v2.13.0 and gated the APT publish step.

For amd64 matrix jobs the change is a no-op. For arm64 matrix jobs on the
amd64 runner, packages that don't compile native code (Python only, or
prebuilt arm64 binaries as in sentinelle-gsm) cross-stamp the .deb fine
with -a arm64. Compiling-from-source arm64 packages aren't a thing in this
repo today.

Verified locally: dpkg-buildpackage -a arm64 -us -uc -b on
secubox-sentinelle-gsm produces a clean
secubox-sentinelle-gsm_0.4.0-1~bookworm1_arm64.deb (with #425's shlibdeps
-Xsecubox-redsea, already on master).
2026-05-30 13:06:22 +02:00
94da816b51 fix(rpi-build): implement --kiosk flag + wire it on rpi400 in CI (closes #423)
The --kiosk flag in image/build-rpi-usb.sh was parsed but never acted on
(INCLUDE_KIOSK toggled but no install block existed), so the rpi400 image
shipped without chromium / X / kiosk service. The boot menu's apply_mode
"kiosk" branch even references a secubox-kiosk.service that was never
created. Adding all the missing pieces:

- New Step 5.4 block (gated by INCLUDE_KIOSK=1):
  - apt install xserver-xorg xinit openbox chromium x11-xserver-utils
  - install image/kiosk/secubox-kiosk.sh → /usr/share/secubox/kiosk/
  - install image/kiosk/xinitrc → /root/.xinitrc
  - create /etc/systemd/system/secubox-kiosk.service (startx on vt7,
    Conflicts with getty@tty7; matches apply_mode's expected unit name)
  - seed /var/lib/secubox/boot-mode = "kiosk" so first boot enters kiosk
  - set default systemd target to graphical.target + enable the unit

- CI build-all-live-usb.yml: add `extra_args: "--kiosk"` to the rpi400
  matrix entry and append `${{ matrix.extra_args }}` to the build invocation.
  Pi 400 = keyboard + HDMI, kiosk-by-default is the obvious user-facing
  shape; other platforms keep their headless default.
2026-05-30 10:04:44 +02:00
CyberMind
97015bbb7f
fix(kernel-build): install build-essential so dpkg-checkbuilddeps passes (#336)
Build #5 cleared the ZRAM choice sed fix (#326) and reached the
bindeb-pkg step, then failed at:

  dpkg-checkbuilddeps: error: Unmet build dependencies:
    build-essential:native libssl-dev

bindeb-pkg auto-generates a debian/control that Build-Depends on
`build-essential:native`. The previous install list pulled in gcc /
make / libc-dev individually but never the meta-package, so
dpkg-checkbuilddeps failed even though all the underlying tools were
present.

libssl-dev is also in the same error line but it IS already installed
— it gets satisfied once build-essential lands because of the way
checkbuilddeps re-resolves the full Build-Depends graph in one pass.

Ref #319 #323 #325 #326.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-22 08:02:01 +02:00
CyberMind
f56ece69ca
fix(kernel-build): force ZRAM_DEF_COMP_ZSTD via sed POST-olddefconfig (#328)
After three rounds of failed attempts (#323, #325, #326), the root cause
is clear: kconfig `choice` blocks are re-resolved by olddefconfig from
their declared `default <member>` in Kconfig, regardless of what's in
.config. `scripts/config --enable ZRAM_DEF_COMP_ZSTD` applied BEFORE
olddefconfig is silently undone by olddefconfig's choice pass; merging
a fragment that sets `CONFIG_ZRAM_DEF_COMP_ZSTD=y` is overridden the
same way.

The only reliable approach is post-olddefconfig sed surgery on the
choice members. Choice members are leaf symbols with no downstream
build-time deps, so no further olddefconfig is needed after the
override.

Workflow change:
  - move scripts/config out of the choice (only set ZSMALLOC/CRYPTO_*)
  - run olddefconfig to resolve the rest of the tree
  - sed the choice into ZSTD (LZORLE off, ZSTD on)
  - log .config before/after the fixup for diagnostics
  - keep the final assertion `^CONFIG_ZRAM_DEF_COMP_ZSTD=y`

Ref #323 #325 #326.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-22 07:05:13 +02:00
CyberMind
8e5e08449f
fix(kernel-build): enforce ZRAM choice via scripts/config after merge (#326)
merge_config.sh + olddefconfig don't always honour choice-symbol
overrides set in a fragment (kconfig special-cases choices). Run
scripts/config after the merge to set ZRAM_DEF_COMP_ZSTD explicitly
and disable the upstream-default ZRAM_DEF_COMP_LZORLE.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-22 06:45:59 +02:00
CyberMind
c24ddcfed3
fix(kernel-build): assert CONFIG_ZRAM_DEF_COMP_ZSTD not the auto-derived string (#323)
CI run 26222437600 failed at the sanity-check: kconfig didn't emit
CONFIG_ZRAM_DEF_COMP="zstd" verbatim because that symbol is the
auto-derived output of the CONFIG_ZRAM_DEF_COMP_<X> choice family,
not a settable variable. Check the choice itself instead.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-21 17:16:15 +02:00
CyberMind
c23d3256e8
ci(kernel-build): GitHub Actions cross-arm64 workflow (closes #297) (#298)
Manual-dispatch workflow that produces a fresh linux-image-*.deb
artifact when source-side kernel config changes (e.g. #295 ZRAM).

* workflow_dispatch inputs: kernel_version (default 6.12.85),
  revision (default 2secubox).
* Steps: checkout, install cross toolchain + build deps, fetch
  upstream tarball, apply repo patches, merge OpenWrt-merged base
  fragment + ZRAM fragment, sanity-grep key configs, run
  `make bindeb-pkg` to cross-build .deb, upload all .debs as
  artifact with 30-day retention.
* Concurrency-grouped on ref so a re-dispatch cancels the old run.
* 90-minute timeout (typical run ~25-40 min).

Operator workflow:
  gh workflow run "Build SecuBox kernel (cross arm64)"
  gh run download <run-id>
  scp linux-image-*.deb root@gk2:/tmp/
  ssh root@gk2 dpkg -i /tmp/linux-image-*.deb
  ssh root@gk2 reboot

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-21 08:47:57 +02:00
CyberMind
edb3ce79b2
ci(build-packages): arch-aware matrix scheduling (closes #203) (#205)
The discover step previously scheduled an amd64 build for every
non-arch-all package, ignoring an explicit `Architecture: arm64`
or `Architecture: amd64` in debian/control. The amd64 job then
failed with `dpkg-genbuildinfo: error: binary build with no
binary artifacts found` because dpkg produces zero binaries for
an arch-foreign declared package on the build host.

Replace the implicit "amd64-always" logic with a case on the
binary stanza's Architecture field:

  all   -> amd64 (the arch-all .deb deployable on any arch)
  any   -> amd64 + arm64 (preserve current behavior)
  amd64 -> amd64 only
  arm64 -> arm64 only

Local dry-run on the current 133-package catalog: 132 amd64 + 1
arm64 combos (secubox-daemon is the only arch-any package), well
under the 256-jobs-per-matrix GH Actions cap.

Read the Architecture from the BINARY stanza (after Package:) so
the Source stanza's Architecture (which Debian convention sometimes
omits) doesn't interfere — awk pattern is `/^Package:/{p=1} p && /^Architecture:/{print $2; exit}`.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 06:38:13 +02:00
CyberMind
3435cfa069
feat(scripts): add check-dashboard-cache.py lint + CI (closes #147) (#148)
Anti-regression for the double-cache pattern documented in CLAUDE.md
(« Performance Patterns — Double Caching »). Catches the bug class that
caused PR #146 (secubox-waf 17 % sustained CPU under SOC polling)
before it lands.

What's added
============
- scripts/check-dashboard-cache.py — AST-based audit. Walks every
  packages/secubox-*/api/main.py, flags hot dashboard routes
  (/stats, /alerts, /summary, /dashboard, /metrics, /overview,
  /events, /history, /recent, /bans, /sessions, /connections)
  whose handler body does per-request I/O (open, read_text,
  read_bytes, subprocess.run, Popen) AND doesn't go through a cache
  (module-level _cache instance + .get() call, OR
  asyncio.create_task(refresh_*) at startup).
    * --check : exit 1 on unjustified violations (CI mode)
    * --report : human-readable table (default)
    * --json : machine-readable

- .cache-lint-allowlist.toml — TOML allowlist for justified
  exceptions. Each entry needs a daemon + route + justification
  (issue link expected). Seeded with the 4 current legacy cases:
  secubox-waf (covered by PR #146 — will drop the entries when
  merged), secubox-config-advisor /history (admin drill-in, not
  polled), secubox-netdiag /connections (real-time TCP state),
  secubox-tor /summary (small file read, follow-up cleanup).

- .github/workflows/dashboard-cache-check.yml — mirror of
  license-check.yml. Runs the lint + the self-tests on PRs that
  touch packages/**/api/main.py, the lint script, the allowlist,
  or the workflow itself.

- docs/CACHE-PATTERN.md — short remediation guide. Three accepted
  shapes (read-through, background-refresh, pure in-memory), code
  example, allowlist syntax, references to the canonical
  implementations (secubox-crowdsec for read-through, secubox-system
  for background-refresh).

Tests (14/14 pass)
==================
- StatsCache pattern detection (compliant cases)
- Non-compliant detection: open, subprocess.run, multiple I/O ops
- Pure in-memory handler = compliant
- Background-refresh task = compliant
- Non-hot route (/health) not audited
- @router.get treated like @app.get
- Allowlist suppresses by exact (daemon, route) key
- Allowlist doesn't cross-pollinate across routes
- Missing allowlist file = no error
- CLI --check exits 1 on unjustified
- CLI --check exits 0 when clean
- CLI --json output well-formed
- **Real repo audit with seeded allowlist passes --check**
  (sanity gate: catches regression if anyone removes an allowlist
  entry without fixing the daemon)

Baseline against the real packages/ tree
========================================
122 daemons audited, 118 compliant, 4 with findings (all
allowlisted). When PR #146 merges, the secubox-waf entries can be
removed from the allowlist — the next lint run will then prove the
fix is wired correctly.

Follow-up
=========
- Drop secubox-waf allowlist entries when #146 merges.
- Per-daemon follow-up issues for the remaining 3 (config-advisor,
  netdiag, tor) — not blocking, allowlist documents the rationale.
- Consider extending HOT_ROUTES to /health / /status once the small
  daemons that call `systemctl is-active` adopt a 10 s cache.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:21:20 +02:00
8e8708f95d ci+packaging: unblock v2.9.0 release — 4 package fixes + partial-release resilience
Five package builds failed on v2.9.0 first attempt, and the release
pipeline cascaded to skip all downstream jobs (collect/publish/images/
live-usb/create-release) because GH Actions treats *any* matrix failure
as a global failure for `needs:` purposes. This commit fixes both
root causes:

Package fixes:
- secubox-eye-square: drop debian/compat (conflicted with control's
  `Build-Depends: debhelper-compat (= 13)`)
- secubox-defaults: same — drop debian/compat
- secubox-metoblizer: switch from legacy `Build-Depends: debhelper
  (>= 13)` (which then requires a debian/compat file) to the modern
  `Build-Depends: debhelper-compat (= 13)` virtual package
- secubox-haproxy: override dh_usrlocal — it can only rehome /usr/local
  directories (Policy 9.1.2), not the individual admin tools we
  deliberately drop there per issue #44

Pipeline resilience:
- build-packages.yml `collect` job: `if: always() && != cancelled` so we
  bundle whatever .deb files the matrix produced even when entries failed
- build-packages.yml `publish` job: predicate now reads collect's success
  rather than the matrix's overall conclusion
- release.yml `build-images`, `build-live-usb`, `publish`,
  `create-release`: all gain `if: always() && needs.build-packages.result
  != 'cancelled'` so a partial build matrix doesn't black-hole the
  release. `create-release` already gracefully skips its
  `if: needs.build-images.result == 'success'` download steps when
  images failed, so the partial release ships what's available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 10:14:50 +02:00
8d02cdc97b ci(build-packages): wire env: for discover inputs + tighten find pattern
Follow-up to the previous matrix-cap fix:

1. YAML/shell quoting hell: the inline ${{ github.event.inputs.arch }}
   substitution inside a single-quoted heredoc broke parsing on push:tags
   events (where inputs are null). Moved both inputs to step `env:` block
   so the shell script reads them as ordinary env vars.

2. Find pattern was `-name control -path "*/debian/*"`, which also matched
   dpkg-build artifacts at `packages/<pkg>/debian/<pkg>/DEBIAN/control` on
   any non-clean checkout. CI's runners are clean so it worked there, but
   the pattern is fragile. Tightened to `-path "*/debian/control" -not
   -path "*/debian/*/DEBIAN/control"`.

Verified locally: 132 amd64 + 2 arm64-eligible = 134 combos, well under
GH Actions' 256 jobs-per-matrix cap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 09:07:21 +02:00
65202dbf9a ci(build-packages): flat matrix to stay under 256-jobs-per-matrix cap
Discover now emits a single flat list of {package, arch} entries
pre-filtered to skip arch-all+arm64 combos. Build uses `matrix.include`
instead of a cross-product, so the job count == filtered combo count
regardless of package catalog size.

Why: with 134 packages, the previous package × [amd64, arm64] expansion
produced 268 matrix jobs, exceeding GitHub Actions' hard 256 cap. The
build job was silently skipped (zero matrix entries scheduled), which
in turn skipped collect → publish → build-images → build-live-usb →
create-release. Releases since v2.7.x have shipped only the installer
ISO artifact for this reason.

The post-discover skip step for "arch-all + arm64" becomes dead code
but remains harmless (the condition can never fire now); leaving in
place so a future re-introduction of cross-product matrices doesn't
silently re-break.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 09:04:27 +02:00
CyberMind
7c37415f88
feat(remote-ui): Phase 1 — extract common/ shared core (ref #127)
* feat(remote-ui/common): scaffold shared-core directory (ref #127)

* feat(remote-ui/common): extract palette.css from round/ (ref #127)

* fix(remote-ui/common): trim palette.css to spec (6 module + 8 C3BOX tokens) (ref #127)

* feat(remote-ui/common): extract base.css verbatim from round/ (ref #127)

* feat(remote-ui/common): extract ICONS to icons.js (ref #127)

* docs(remote-ui/common): correct icons.js header comment — sizes are {22,48,96} not 128 (ref #127)

* feat(remote-ui/common): extract RINGS + CX/CY/SA to modules-table.js (ref #127)

* feat(remote-ui/common): extract CFG to config.js (replaces jwt-helper.js per #127 plan revision)

* feat(remote-ui/common): extract TransportManager with onModuleTap/onTransportChange hooks (ref #127)

* feat(remote-ui/common): extract SIM + simStep to sim.js (ref #127)

* feat(remote-ui/common): move 24 SecuBox module PNG icons to common/assets/icons/ (ref #127)

* feat(remote-ui/common): move secubox-otg-gadget.sh, add GADGET_NAME env override + arm64 serial fallback (ref #127)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(remote-ui/common): trim whitespace from device-tree serial-number read (ref #127)

* feat(remote-ui/common): move secubox-otg-host-up.sh + variant-aware comment (ref #127)

* refactor(remote-ui/round): consume common/ via <link>/<script> tags (ref #127)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(secubox-system): add form_factor to RemoteUIConnectedRequest with TDD (ref #127)

* feat(remote-ui/round): deploy.sh bundles common/ alongside round/ (ref #127)

* fix(remote-ui/round): deploy.sh COMMON_SRC path resolution + rsync --delete (ref #127)

* feat(remote-ui/round): build-eye-remote-image.sh embeds common/ + nginx /common/ alias (ref #127)

* docs(remote-ui): document common/ dependency in round/ docs (ref #127)

* docs(remote-ui/round): clarify palette.css is forward-looking (ref #127)

* docs(remote-ui): Task 18 regression-gate report — structural verification (ref #127)

Full diffoscope gate blocked by missing hyperpixel2r.dtbo prerequisite.
Structural equivalence verified instead: Phase 1 changes are purely
additive (common/ embed + nginx /common/ alias + extracted JS/CSS/icons),
no behavioural change to round/'s existing logic.

User must run the full image diffoscope manually after sourcing the
hyperpixel2r.dtbo blob, before final merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(eye-remote): bump workflow VERSION env 2.2.0 → 2.2.1 (ref #127)

Pre-existing drift: build-eye-remote-image.sh writes
secubox-eye-remote-2.2.1.img but the workflow's Compress/Checksum/
Upload steps reference ${{ env.VERSION }} = 2.2.0, so the compress
step fails with "No such file or directory" after a successful build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 05:59:40 +02:00
4d937995ba ci(license): add License Headers workflow (ref #81)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:00:54 +02:00
bd7dda0c6f feat(secubox): complete meta-script generator Tasks 14-17
Task 14: Arch Profiles
- Add profiles/arch/arm64.yaml and profiles/arch/amd64.yaml
- Add ResolveWithArch() to merger for base → arch → tier chain
- Add tests for arch profile resolution

Task 15: Package secubox.yaml for All Packages
- Add scripts/generate-secubox-yaml.py generator script
- Generate 131 debian/secubox.yaml files with:
  - Category detection (security, network, system, etc.)
  - Tier assignment (all, lite, standard, pro)
  - API socket and UI path detection

Task 16: APT Repository Setup
- Add apt/conf/ reprepro configuration (multi-arch arm64/amd64)
- Add apt/hooks/lintian-check pre-publish validation
- Add scripts/apt-publish.sh and scripts/apt-sync.sh
- Add apt/README.md documentation

Task 17: CI Integration
- Add .github/workflows/build-secubox-cli.yml
- Build for linux-amd64 and linux-arm64
- Version injection via ldflags
- GitHub releases on tag push

Code Quality Fixes (Tasks 10-13):
- Add atomic writes for OTA boot control files (0600 perms)
- Fix NVME device extraction (nvme0n1p2 → nvme0n1)
- Add scanner.Err() checks in hardware detection
- Fix URL injection validation in fetch command
- Add proper cleanup on checksum failures

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-11 05:32:29 +02:00
45c2b7c020 feat: Add metoblizer, streamlit power management, replace espressobin with mochabin
- Add secubox-metoblizer package (centralized log aggregator)
- Streamlit: double-buffer caching, power management UI, autostart
- Streamlit UI: consolidate Components into Status tab
- GitHub Actions: replace espressobin-v7 with mochabin for live USB builds
- Various UI improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-10 18:37:58 +02:00
fa92fe722c feat(ci): Unified sync-all workflow + eyemote visual banner
- Add .github/workflows/sync-all.yml: unified CI/CD on all pushes
  - Discovers changed packages and computes project metrics
  - Auto-updates README badges (packages, migration, endpoints)
  - Auto-updates WIP.md with CI sync entries
  - Creates releases on tags
  - Generates GitHub step summary with metrics table
- Add docs/assets/secubox-eyemote-banner.svg: 6-ring status SVG
  - Matches Round UI design (AUTH/WALL/BOOT/MIND/ROOT/MESH rings)
  - Displays live metrics: 131 packages, 2000+ endpoints, 94% migration
  - Cyberpunk/hermetic palette with glow effects
- Update README.md: add eyemote banner at top
- Update docs/wiki/Home.md: add eyemote banner at top

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-10 09:28:00 +02:00
555600d5dd fix(multiboot): Ensure kernel files are properly copied to EFI partition
- Fix glob pattern in bash test (glob in [[ -f ]] doesn't work correctly)
- Use find command instead of glob for reliable kernel detection
- Add fallback to extract ARM64 kernel from live USB image if not in rootfs
- Add verification step in GitHub Actions to check boot files after build
- Sort kernel files by version to get latest when multiple exist

Fixes missing vmlinuz/Image on multiboot USB issue.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 19:29:09 +02:00
d42745aac3 feat(live-boot): Complete live RAM boot implementation v2.2.4-live
- Install live-boot package and rebuild initramfs with live-boot scripts
- Create squashfs filesystem (878MB) on data partition sda4
- Update boot.scr with live boot parameters (boot=live, toram)
- Fix wiki sidebar links from [[Page|Display]] to [Display](Page)
- Add Eye-Remote wiki page documentation
- Add sync-wiki.sh script for wiki repository sync
- Add patch-multiboot-efi.sh for post-build EFI patching

Partition layout:
- sda1 (512MB): EFI with kernel, initrd, dtbs, boot.scr
- sda2 (3GB): ARM64 rootfs reference
- sda3 (3GB): x86 rootfs for VirtualBox/QEMU
- sda4 (9.5GB): Data + /live/filesystem.squashfs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 13:30:50 +02:00
2e24fbb5fd ci(multiboot): Add GitHub Action for multiboot image builds
- Create build-multiboot.yml workflow with manual dispatch
- Support configurable image sizes (8/16/32GB)
- Build .deb packages first, then create multiboot image
- QEMU user-mode for cross-arch debootstrap
- XZ compression and GitHub Release integration
- Optional desktop environment inclusion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 11:04:28 +02:00
9516379e93 ci(eye-remote): Add v2.2.0 build workflow with menu system tests
- Add test-menu-system job for pytest validation
- Update VERSION to 2.2.0
- Add create_release manual trigger option
- Update release notes with radial menu features
- Change tag pattern to eye-remote-v* for clarity
- Add PR trigger for CI on changes

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-24 11:49:07 +02:00
be92d7df0b docs(eye-remote): Add hardware wiki + sync CI workflow
- Eye-Remote-Hardware.md: GPIO pinout, USB OTG, DPI timings, gadget modes
- Update CI workflow to v2.0.0
- Fix build script: add DNS for chroot network access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-22 08:56:21 +02:00
8f3d446a07 feat(eye-remote): OFFLINE mode v1.9.0 - pre-install packages via QEMU
Complete rewrite of build-eye-remote-image.sh for pure offline boot:

- Use QEMU ARM chroot to pre-install all packages at build time
- Expand image by 1GB for pre-installed packages (~500MB)
- Pre-installed: chromium, nginx, lightdm, openbox, python3-pil
- Configure lightdm autologin, openbox autostart, nginx in chroot
- Create secubox user with all groups during build
- No rc.local/firstrun needed - boots directly into kiosk

Build requirements: qemu-user-static, binfmt-support

Boot time comparison:
- v1.8.x: ~10 min (package download required)
- v1.9.0: ~60 sec (ready immediately, no internet)

Closes #30

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-20 21:10:56 +02:00
5b6da8a588 ci: Add GitHub Action for Eye Remote image build
- Downloads RPi OS Lite automatically
- Builds complete Eye Remote SD card image
- Compresses with xz and generates checksums
- Uploads to releases on version tags
- Supports manual trigger with WiFi/hostname options
- Part of Eye Remote v1.8.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-20 12:12:11 +02:00
f4806bf7fa fix(ci): Fix eMMC image check and RPi multi-initrd copy
- build-all-live-usb.yml: Check for .img.gz first since build-image.sh
  already compresses and removes the .img file
- build-rpi-usb.sh: Handle multiple kernel/initrd files by selecting
  the latest version instead of globbing which breaks cp

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-15 09:22:23 +02:00
4165d6d66c feat(network): Smart auto-IP with ARP collision detection (v1.7.0.2)
- Add ARP-based IP collision detection for multi-device environments
- MAC-based pseudo-random IP offset to spread devices across range
- Gratuitous ARP announcement to prevent IP conflicts
- Fix EspressoBin DSA network: target wan interface, not eth0 CPU port
- Static IP fallback 192.168.255.250 when DHCP unavailable
- Sync all build scripts to version 1.7.0
- Add screenshot script with 90+ module URLs
- Add mock HTML screenshots for documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-14 16:28:02 +02:00
698a0c728f fix(ci): Fix matrix context in workflow job-level if condition
GitHub Actions doesn't allow matrix.* in job-level 'if' conditions.
Moved platform filtering to step-level with skip output variable.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-13 10:19:13 +02:00
6c7e6051bd feat(ci): Add unified multi-platform live USB workflow
- Add build-all-live-usb.yml with matrix for x64, EspressoBin V7, and RPi 400
- Update release.yml to include live USB builds in release pipeline
- Add RPi 400 netplan configuration for Ethernet and WiFi
- Deprecate build-live-usb.yml (now wrapper to unified workflow)

Platforms supported:
- x64 (amd64) - GRUB UEFI/BIOS boot
- EspressoBin V7 (arm64) - U-Boot distroboot with embedded eMMC image
- Raspberry Pi 400 (arm64) - Native Pi firmware boot

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-11 11:20:46 +02:00
17f4886a7f fix: Handle duplicate assets in release workflow retries
- Add step to delete existing assets before upload (handles workflow retries)
- Update to softprops/action-gh-release@v2
- Add fail_on_unmatched_files: false for graceful handling

Fixes 422 error when retrying failed release uploads.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-08 16:11:05 +02:00
5ebc80fc4b fix: Handle missing GPG_PRIVATE_KEY in CI publish job
Skip signing and deploy steps when secrets are not configured
instead of failing the entire workflow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-08 10:07:11 +02:00
d7fdc4186e feat: Add QEMU ARM64 VM support and RPi 400 to releases
- Add create-qemu-arm64-vm.sh script for ARM64 emulation on x86 hosts
- Add wiki/QEMU-ARM64.md documentation
- Update CI workflows to include RPi 400 and VM scripts in releases
- Update release notes to document all platforms

Platforms now supported:
- MOCHAbin (Armada 7040)
- ESPRESSObin v7/Ultra (Armada 3720)
- Raspberry Pi 400 / Pi 4
- VirtualBox x64
- QEMU ARM64 emulation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-08 08:13:56 +02:00
c292685990 fix: Add chown after sudo build in ISO workflow
Files created by sudo are root-owned, preventing subsequent
steps from accessing them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-07 07:29:32 +02:00
c7bf0b9447 feat: Add Raspberry Pi 400 support with boot menu
- Add rpi400 to default CI builds in build-image.yml
- Create board/rpi400/config.mk with Pi 400 settings
- Add build-image.sh redirect to build-rpi-usb.sh for RPi boards
- Add boot menu system to build-rpi-usb.sh:
  - Normal, Kiosk, Console, Bridge, Minimal modes
  - VT100/DEC PDP-style menu interface
  - Persistent mode selection across reboots
  - systemd integration for early boot
- Fix slipstream in build-rpi-usb.sh:
  - Use dpkg --force-depends (pip provides Python deps)
  - Skip failing apt-get -f install
  - Add more Python dependencies to pip install

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-07 06:32:56 +02:00
4772fc2b0f fix: Use board-specific image sizes for eMMC compatibility
Board configs now define IMG_SIZE:
- ESPRESSObin v7: 3584M (fits 4GB eMMC)
- ESPRESSObin Ultra: 4G (8GB eMMC)
- MOCHAbin: 4G (8GB eMMC + SATA)

CI workflow updated to use board defaults instead of hardcoded 8G.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-05 15:20:24 +02:00
38841a9640 fix(ci): Include all SecuBox packages in image builds
- build-image.yml: Download packages from build-packages workflow
  and pass --slipstream flag to include them in images
- build-live-usb.yml: Remove redundant cache copy, improve logging
- release.yml: Update package count from 93 to 124
- build-image.yml: Update package count from 33 to 124

All 124 SecuBox packages will now be slipstreamed into live USB
and system images when built via CI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-04 12:49:11 +02:00
a2fd0e0cd6 feat(boot): CRT-style banners with colors and emoji indicators
Boot Banner Improvements:
- /etc/issue: Gold ASCII art pre-login banner with credentials
- /etc/motd: Colorful LIVE USB banner with access info
- secubox-status: New command showing system overview with CRT colors
- secubox-help: Quick reference for all secubox commands
- secubox-logs: Live security log viewer shortcut
- profile.d: Login status display with mode/service/IP indicators

Mode Switching:
- cmdline-handler: Fixed TUI mode to start (not just enable) service
- secubox-mode: Updated with CRT colors and emoji status indicators

GRUB Menu:
- Kiosk GUI is now default when --kiosk flag used
- All entries have emoji indicators (🖼️📟🌉🛡️💾🚀🔧🚨🐛)
- CRT-style menu colors (cyan on black, yellow highlights)

CI Workflows:
- build-live-usb.yml: Updated boot options and credentials in release notes
- release.yml: Updated to 93 packages, new boot options, correct credentials

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-04 12:16:40 +02:00
b372463fba fix(ci): Add workflow_call trigger to enable reusable workflows
- build-packages.yml: Add workflow_call with secrets
- build-image.yml: Add workflow_call with inputs, fix matrix for all event types
- publish-packages.yml: Add workflow_call with inputs and secrets

This fixes the release.yml workflow which was failing because it tried
to call these workflows as reusable workflows without the workflow_call
trigger defined.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-04 10:54:52 +02:00
8abe743c40 fix(ci): Build Go c3box binary and pre-build soc-web in CI
- Add c3box binary build alongside secuboxd and secuboxctl
- Pre-build React app for soc-web before dpkg-buildpackage
- Update soc-web debian/rules to skip npm if dist/ pre-built
- Remove nodejs/npm Build-Depends (now pre-built in CI)

Fixes build failures for secubox-daemon and secubox-soc-web packages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-04 07:56:45 +02:00