8 Commits

Author SHA1 Message Date
librelad
3653a39fd8 chore(config): quiet per-file reconcile output, drop backup note
The config reconcile pass printed one 'Reconciled config: <name>  (backup:
.<name>.bak)' line per changed file. Drop the per-file message entirely:
the intro notice and the two per-section '...completed.' confirmations are
enough, and the backup mention added noise. The hidden .<file>.bak sibling
is still written for safety — it's just no longer announced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-06-17 17:30:36 +01:00
librelad
87e19e197a fix(config): hide reconcile backups as dot-named siblings; guard the option resolver
Reconcile backups now land as .<file>.bak instead of <file>.bak, so they
no longer clutter the configs folder. The .bak suffix is kept, so every
existing walker/sourcing exclusion still applies.

Also exclude dotfiles and *.bak from findConfigFileForOption: it walked
the configs tree with no backup exclusion, so depending on directory
order a 'config update' could resolve a key to the backup file and write
the user's change there — silently lost.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-06-12 23:11:14 +01:00
librelad
7c28007779 refactor(config): updater knobs -> configs/webui/webui_updater; fix config heal/reconcile gaps
Move the WebUI-updater settings out of general_terminal into their own
advanced webui-category file (webui_logs precedent): new
configs/webui/webui_updater holds CFG_UPDATER_SCAN_INTERVAL and the
migrated CFG_HOTFIX_AUTO, listed in webui/.category.

The move only reaches existing installs if the config convergence
machinery works, and three pieces of it silently didn't:

- checkConfigFilesMissingFiles walked a stale hardcoded category list
  ('general features network' — features doesn't exist; webui/backup/
  security never healed). Derive the categories from the template tree
  instead, and heal .category metadata too: copy it when absent and
  merge missing SUBCATEGORY_ORDER entries when present, so healed files
  actually appear in the WebUI Config editor. core_categories removed.
- Option reconciliation never touched ANY nested config file: configs_dir
  carries a trailing slash, so rel stripping missed ('configs//'), the
  template lookup failed, and reconcileConfigFile early-returned for
  every file. Strip the slash before matching.
- reconcileConfigFile's AUTO_DELETE=false branch read a never-populated
  live_line array, losing the dropped keys it promised to keep. Populate
  it alongside live_value.

Also exclude *.bak from config sourcing (reconciliation writes <file>.bak
next to live configs — now that it runs, sourcing backups would resurrect
deleted keys), and add 'libreportal config check' as a non-interactive
front door to the converge pass (was only reachable via install flows and
the interactive menu).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-06-12 22:33:23 +01:00
librelad
f49455e38e fix(de-sudo): route all confirmed container-tree writes through the privileged path
Exhaustive audit (workflow: 19 finders + adversarial per-file verify; 85 raw ->
66 unique -> 39 confirmed) found 36 direct writes into the container-owned tree
that bypass runFileOp/runFileWrite/runCfgOp (manager => EACCES in rootless) plus
3 $?-masking sites. Fixes by area:

- apps: grafana + prometheus install hooks (sudo chmod -> runFileOp chmod);
  gluetun provider etag (tee -> runFileWrite).
- webui generators: task-create (10 sites: mkdir/chown/tee/jq|tee/sed|tee ->
  runFileOp/runFileWrite); app-icons (mkdir/cp/mv); config icon cp; system
  metrics + update throttle stamps (runAsManager touch -> runFileOp touch);
  setup-lock rm; updater history seed + cp.
- task health checker: 4 log writes (tee -a -> runFileWrite -a) + 3 find -delete
  (-> runFileOp find).
- config reconcile: backup cp -> runCfgOp; live cp -> runFileWrite < tmp for
  container-owned configs (the container user can't read a manager 0600 tmp).
- peer pull: tar extract into the container tree -> runFileOp tar.
- masking: ip_find_available + folder_group(x2) — split 'local VAR=$(cmd)' so $?
  reaches the following [[ $? ]] check.

15 files, all pass bash -n; fixed idioms confirmed gone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-31 03:50:48 +01:00
librelad
ea59d5b268 feat(config): reconcileConfigFile now syncs comments from template (preserves user values)
Existing installs were locked out of template-side description /
options / marker changes because reconciliation kept the user's whole
`CFG_KEY=value     # comment` line verbatim. So new metadata like the
**DEV** marker I'm adding for the developer-mode feature wouldn't take
effect on already-deployed boxes — only fresh installs.

Updated reconcileConfigFile to split each line into value-part and
comment-part. User value is still sacred; the comment (title,
description, [options], **ADVANCED**/**DEV** markers) now comes from
the template. Field renames, label tweaks, marker additions/removals
shipped in a release reach existing installs on the next CLI
invocation (which runs the reconciler).

Specifically unblocks: the developer-mode WebUI feature (CFG_DEV_MODE
field gets added by the existing add-only path; CFG_INSTALL_MODE and
CFG_RELEASE_CHANNEL now pick up their new **DEV** markers and the
'Release - Stable' / 'Bleeding Edge' labels).

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 23:53:21 +01:00
librelad
92c0261ca4 refactor(de-sudo): config-plane + permission helpers off raw sudo
config_scan_variables + config_check_missing operate on the manager-owned
configs_dir -> runInstallOp (test/cat/cmp/cp/mkdir). Container-path chmods in
before_start (traefik) + config.sh -> runFileOp. Fix the 'sudo sudo chown'
double in root_file.sh -> runSystem chown (ownership establishment).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-24 17:03:19 +01:00
librelad
d3681163af feat(config): regenerate config files from template (batch add + delete)
Replaces the slow, interactive per-variable scan with a deterministic
reconcile: each live config is rebuilt from its (freshly-cloned) template —
keeping the user's existing values, adding new template keys
(CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE), and dropping keys the template no
longer defines (new CFG_REQUIREMENT_CONFIGS_AUTO_DELETE, default true).
Structure/order/comments follow the template; non-interactive; atomic with a
.bak; refuses to act on a missing/empty template so a broken clone can't wipe
a config. Applies to both general and per-app configs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-22 11:38:22 +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