7 Commits

Author SHA1 Message Date
librelad
a4d3b78cdb feat(debug): LP_LOAD_TRACE + 'libreportal debug load-trace' (lazy-load Phase 1)
First step toward an autoload-style lazy loader for the 499-file source
tree (current cold load ~1s wall / 340ms user-time per CLI invocation,
mostly spent sourcing files the command never calls). This commit only
measures — no behaviour change unless LP_LOAD_TRACE=1.

LP_LOAD_TRACE=1 instrumentation (scripts/source/loading/initilize_files.sh):
  Wraps each  in the main file-list loop with EPOCHREALTIME
  before/after, writes `<elapsed_ms>\t<file_relpath>` to
  $LP_LOAD_TRACE_FILE (default /tmp/libreportal-load-trace.<pid>.log).
  Zero overhead when the env var is unset (one [[ test per file).

libreportal debug load-trace [cmd...]:
  New `debug` CLI category. Spawns a child `libreportal <args>` (default
  'help') with LP_LOAD_TRACE=1, then awk-aggregates the trace: wall vs
  cumulative source time, file count, top-15 hottest files. The diff
  between wall and cumulative-source = bash startup + dispatch + the
  command's own work.

Used in the next phases to (a) validate that the lazy loader actually
delivers the speedup we expect and (b) flag any single file that hogs
disproportionate time (rare `heredoc | sed | base64` style work at
source time would show up here as a >10ms entry).

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 20:33:22 +01:00
librelad
d4bab9bb1b fix(init): skip the routine update check on the first install run
Triage of a broken fresh install:
  1. init.sh → all root setup → completeInitMessage hands off to
     `libreportal run install` as the manager.
  2. start.sh sources load_sources.sh, which calls sourceCheckFiles "run".
  3. sourceCheckFiles "run" calls checkUpdates — its only path to startLoad on
     a non-local mode is via the git/release recovery branches.
  4. git fails (the deployed install dir has no .git), lpFetchRelease fails (no
     reachable release manifest), none of the recovery branches converge on
     startLoad, and the install silently exits with WebUI + service unset.

Fix: completeInitMessage exports LIBREPORTAL_INITIAL_INSTALL=1, and the
sourceCheckFiles "run" branch calls startLoad directly when that's set — same
endpoint the local-mode branch hits. We just installed the latest code from
this tree; checking for updates on the first run was nonsensical and the
recovery gauntlet would only break things.

Confirmed by re-running uninstall + install: the install now reaches the
Pre-Installation / database / WebUI build / crontab / WebUI compose-up steps
and produces a working WebUI. (A separate compose-tag bug surfaced next —
fixed in the follow-up commit.)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 17:26:40 +01:00
librelad
cdb2fc633d fix(install): establish container layer in root phase (real fix for scan noise)
Reverts the 2>/dev/null band-aids and fixes the root cause. The
manager-run install boot scans app configs under /docker/containers AS
the container user (runFileOp). But init.sh's initFolders creates that
dir manager-owned, and the handover to the container user happened later
(start_preinstall), AFTER the boot scans — so the scans ran as the
container user against a dir it didn't own yet: "find:
'/docker/containers/': Permission denied" (cosmetic; the dir is empty
that early, but it's the wrong ownership at the wrong time).

Add initContainerLayer() to init.sh's root phase (after initGIT +
initUpdateConfigs, before the manager-run handoff): rootless-only, it
creates the docker-install user if missing and chowns /docker/containers
to it (751). The later rootless setup is now idempotent — it finds the
user existing and just (re)asserts its password + daemon config (moved
updateDockerInstallPassword out of the create-only branch). Rooted is
unaffected (containers stay manager-owned, which the manager reads).

Result: by the time the boot scans run, /docker/containers is owned by
the user doing the scanning — no permission error, nothing suppressed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-24 22:53:11 +01:00
librelad
32c33e27be fix(install): silence find-permission noise on early best-effort scans
Early in an install the docker-type config isn't loaded yet, so runFileOp
falls back to the manager, which can't list the container-owned (751)
/docker/containers/ dir. Two best-effort scans then leaked
"find: '/docker/containers/': Permission denied" to the install output
(x3 per run): scan_files.sh's app_configs scan and the application config
reconcile. No app configs exist that early on a fresh install, so the
empty result is correct — just suppress the find stderr (the -print0
output still flows). Cosmetic only; doesn't change what's enumerated once
the config is loaded.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-24 22:39:43 +01:00
librelad
13d2c15074 fix(desudo): de-sudo config scan so the manager runtime loads CFG
scan_files used 'sudo find' to enumerate config files to source. Under the
scoped sudoers that's denied, so NO configs got sourced -> CFG_DOCKER_INSTALL_TYPE
ended up empty -> runFileOp/runFileWrite fell back to the manager branch and
every container-path write failed. Root cause of the 'sudo: a password is
required' + 'tee: Permission denied' storm when running under the scoped grant.

- configs/ scan (manager-owned): plain find
- app_configs scan (/docker/containers, docker-install-owned, not list-readable
  by the manager): runFileOp find (enumerate as that user; manager still sources
  each .config, which is o+r). 'containers' install templates stay plain find.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-24 18:38:19 +01:00
librelad
300301e6aa style(cli): carry glyph markers through the install scripts
Propagate the ✓ Success / ✗ Error / ! Notice / ❯ Question glyphs (from markers.sh) through the rest of the pipeline: swap the inlined helpers in init.sh and generate_arrays.sh, and replace raw echo -e "${RED}ERROR:${NC}" calls with the isX helpers in config_check_missing.sh, check_success.sh, initilize_files.sh, and reset_git.sh.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-22 13:25:59 +01:00
librelad
875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00