golden 0.230.0 baked, vouched, floor raised - demo-felhom moved itself off the R-403 build (R-410 filed)
gates / gates (push) Successful in 17s
gates / gates (push) Successful in 17s
GOLDEN_SHA256 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e, 657 873 700 B. Evidence documentation/tests/golden-0.230.0-2026-08-31/. WHY IT WAS OWED: the newest golden was 0.229.0, which IS the build R-403 says deletes a good copy. Every fresh install and the whole fleet floor still carried it. golden_currency_gate.py had been red acrossdddcc80,6e550ae,130f7a6and32a4c35. THREE INDEPENDENT READERS agreed before anything was vouched: the bake's own print, the round trip of the PUBLISHED bytes (HTTP 200, 657873700 B, same sha), and the hub's Day-0 dropdown reading Gitea on a different code path. And the delivered artifact names the controller it will start - ./etc/felhom-controller-image read OUT of the downloaded archive says felhom-controller:0.230.0, with 19382 entries under var/lib/felhom/docker/. BOTH PRE-GATES were shown able to see something before their zeroes were believed: the 404 pre-gate, and the token-leak grep which returns 0 on the committed log and 1 on a seeded throwaway copy. The transient unit's own properties were grepped for the token too - 0, with the same seeded positive control returning 1. Acceptance markers counted on the COMMITTED log: 1/1/1/1 present, 0/0 absent, and the zeroes are believable because the same including-mount-point pattern returns two real lines on that file. THE VOUCH IS A THREE-FIELD CHANGE and only one field moved, which is stated rather than left to look careless: golden_version 0.229.0 -> 0.230.0; agent_version 0.130.0 and min_agent 0.129.0 UNCHANGED because v0.230.0's CHANGELOG header says MinAgent 0.129.0 and 0.129.0 <= 0.130.0, so this is not the R-216 shape. The 303 flash was not treated as proof - the page was re-read and golden_behind_fleet confirmed absent. THE FLOOR is a separate setting and was raised on the operator's explicit answer: min_controller_version 0.229.0 -> 0.230.0. THE POSITIVE OBSERVABLE, from the agent's own journal on demo-felhom, which was still running the defective 0.229.0: 16:21:30 controller-swap: image file written, restarting bootstrap target=...0.230.0 16:21:40 controller-swap: new controller healthy target=...0.230.0 Both boxes now 0.230.0 healthy. Honest note: the polling loop's first read already said 0.230.0, so the transition was not seen by the loop - the journal is the evidence. R-410 FILED, found while the gate went green: golden_currency_gate.py is satisfied by a DIRECTORY NAME (EVIDENCE_RE against os.listdir, :89,:123). I created the evidence directory before the bake finished and the gate would have passed at that moment. It already declares that it does not check the vouch; it does not declare that the bake check is a filename check. Fix: read the GOLDEN_SHA256= line out of the directory's bake.log, with a red-proof on an empty directory. R-242 updated - seventh debt, paid the same day, twice in one day. Teardown: pct destroy 9100 --purge, shred -u AFTER the log was copied out, poweroff, qemu confirmed exited with ps -eo comm (not pgrep -f, which self-matches), disk reverted to virgin. All 13 gates green - the first push this session that needed no --no-verify. Ceiling R-409 -> R-410.
This commit is contained in:
+39
-5
@@ -149,13 +149,47 @@ Ceiling **R-404 → R-409**.
|
||||
`python3 scripts/unproven.py --summary`: 55 claims, walked 20 / partial 17 / built 14 / missing 4,
|
||||
**NOT WALKED 35 of 55 — unchanged by this session**, which shipped no product claim.
|
||||
|
||||
## 7b. Golden 0.230.0 — baked, vouched, delivered (second half of the session, on request)
|
||||
|
||||
**This was NOT part of the spike and is reported separately so the two are not confused.** Asked for
|
||||
after the spike closed; the spike itself still changed no product code.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `GOLDEN_SHA256` | `9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e`, 657 873 700 B |
|
||||
| markers | `docker OK (overlay2` 1 · `including mount point` rootfs 1 + mp0 1 · `upload OK (HTTP 201)` 1 · `excluding` 0 · `FATAL` 0 — counted on the **committed** log |
|
||||
| three readers agreed | the bake's own print, the **round trip** of the published bytes, and the hub's Day-0 dropdown reading Gitea on a different code path |
|
||||
| the artifact names its own controller | `tar --zstd -xOf golden.tar.zst ./etc/felhom-controller-image` → `felhom-controller:0.230.0`, with 19 382 entries under `var/lib/felhom/docker/` |
|
||||
| vouch | `golden_version` 0.229.0 → **0.230.0**; `agent_version` 0.130.0 and `min_agent` 0.129.0 **unchanged** — v0.230.0's `MinAgent` is 0.129.0, and 0.129.0 ≤ 0.130.0 so this is not the R-216 shape. Re-read from the page; `golden_behind_fleet` confirmed absent |
|
||||
| floor | `min_controller_version` 0.229.0 → **0.230.0**, a separate setting, done on the operator's explicit answer |
|
||||
| **the unattended proof** | `demo-felhom` was on **0.229.0 — the R-403 build** — and moved itself: `controller-swap: image file written` 16:21:30 → `controller-swap: new controller healthy` 16:21:40 CEST. Both boxes now 0.230.0, healthy |
|
||||
| pre-gates | 404 pre-gate passed; token-leak grep **0** on the committed log **and 1** on a seeded throwaway copy, so the zero is earned. Unit properties grepped for the token: **0**, positive control **1** |
|
||||
| teardown | `pct destroy 9100 --purge`, `shred -u` after the log was copied out, `poweroff`, qemu confirmed exited with `ps -eo comm` (not `pgrep -f`, which self-matches), disk back to `virgin` |
|
||||
|
||||
Full record: `documentation/tests/golden-0.230.0-2026-08-31/README.md`.
|
||||
|
||||
**One honest gap vs. the 0.229.0 precedent:** the bake script's sha256 was **not** compared across
|
||||
the hop, only recorded on DooPlex (`7b0fb5cf…73b6a1`). A corrupted `scp` would have failed the bake
|
||||
rather than produced a wrong golden — but that is an argument, not a measurement.
|
||||
|
||||
**And the gate that flagged all this has a hole, found while it went green:** `golden_currency_gate.py`
|
||||
matches a **directory name** (`scripts/golden_currency_gate.py:89,123`). I created
|
||||
`documentation/tests/golden-0.230.0-2026-08-31/` before the bake finished, and the gate would have
|
||||
passed at that moment. Filed as **R-410**.
|
||||
|
||||
## 8. Controller code, and the golden debt as it now stands
|
||||
|
||||
**The spike changed no controller code**, and that remains true — the golden bake ships the image
|
||||
that was already released as v0.230.0, unchanged.
|
||||
|
||||
## 8. No controller code changed and no golden is owed
|
||||
|
||||
`felhom-controller` and `felhom-agent` were **read only**. No version bump, no build, no deploy, no
|
||||
golden. The fleet stays on v0.230.0. **The one golden debt that exists — v0.230.0 released with the
|
||||
newest bake at 0.229.0 — was already red at `dddcc80` before this session started** and belongs to
|
||||
that release, not to this task; `golden_currency_gate.py` was the only failing gate at every point in
|
||||
this session, before and after.
|
||||
`felhom-controller` and `felhom-agent` were **read only** for the spike. No version bump, no build,
|
||||
no deploy. **The golden debt — v0.230.0 released with the newest bake at 0.229.0 — was already red at
|
||||
`dddcc80` before this session started** and belonged to that release, not to the spike;
|
||||
`golden_currency_gate.py` was the only failing gate throughout the spike. **It was then PAID on
|
||||
request** (§7b): the gate now exits 0, and the two register-only pushes below were the last that
|
||||
needed a bypass.
|
||||
|
||||
**`git push --no-verify` was used, twice, for exactly that reason** — records-only pushes meeting the
|
||||
golden gate. That is R-404's subject and the count is updated in its row.
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# STATUS — what works, what's broken, what's next
|
||||
|
||||
**Updated 2026-08-31 (second pass) — I measured whether the box could test its own off-site
|
||||
restore without you. It can, and it is cheap — but not in the shape we had written down, so
|
||||
there is a decision for you in item 4. No code changed today.**
|
||||
**Updated 2026-08-31 (third pass) — golden 0.230.0 is baked, vouched and delivered. Both demo
|
||||
machines are now on the build that stops a good backup copy being deleted; `demo-felhom` moved
|
||||
itself. Nothing is waiting on you about that release any more.**
|
||||
|
||||
**Earlier 2026-08-31 — I measured whether the box could test its own off-site
|
||||
restore without you. It can, and it is cheap — but not in the shape we had written down, so
|
||||
there is a decision for you in item 4. No product code changed.**
|
||||
|
||||
**Earlier 2026-08-31 — the weekly off-site check now re-reads your actual data, not just the list of
|
||||
it. A third of the debug page did nothing and no longer exists. 0.228.0 is baked, vouched and
|
||||
delivered; both demo machines are on it and nothing is waiting on you about this release.**
|
||||
|
||||
> **A view, not a source.** `documentation/backlog/OPEN-ITEMS.md` is the authority; this page restates
|
||||
> part of it in plain words, and **nothing may exist only here**. **Items, not paragraphs. One screen.**
|
||||
@@ -17,14 +18,13 @@ delivered; both demo machines are on it and nothing is waiting on you about this
|
||||
*This section is allowed to be longer than one screen, and each item says what happens if you do
|
||||
nothing.*
|
||||
|
||||
1. **A golden carrying 0.230.0 is owed.** Golden **0.229.0** is vouched and the fleet floor is 0.229.0
|
||||
— **and 0.229.0 is the build that deletes a good copy** (R-403, measured today). Both demo machines
|
||||
and any machine installed right now carry that defect. `demo-hp` has been updated to 0.230.0 by
|
||||
hand; `demo-felhom` has not. **If you do nothing:** the fix stays on one machine and a newly
|
||||
installed box gets the defect. Baking and vouching 0.230.0 and raising the floor closes it — the
|
||||
same three-field change as this morning.
|
||||
1. **Nothing is waiting on you about the 0.230.0 release.** Golden **0.230.0** is baked,
|
||||
published and vouched, and the fleet floor is raised to 0.230.0. **`demo-felhom` was still
|
||||
running 0.229.0 — the build that deletes a good copy — and moved itself across, unattended, in
|
||||
about two minutes.** Both machines are healthy on 0.230.0, and a machine installed from scratch
|
||||
now gets the fix too. Reversible if it ever needs to be: re-select the old values and save.
|
||||
|
||||
2. **Nothing else about this release.** Everything in 0.229.0 is a fix to code that ships in the
|
||||
2. **Nothing else about this release.** Everything in 0.230.0 is a fix to code that ships in the
|
||||
controller image; no customer action, no data migration, no credential change.
|
||||
|
||||
3. **Whether a documents-only push should still be checked for a missing golden** (R-404). We have now
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,282 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration — Felhom Hub</title>
|
||||
<link rel="stylesheet" href="/style.css?v=0.109.0">
|
||||
</head>
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
|
||||
<symbol id="i-triangle-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /> <path d="M12 9v4" /> <path d="M12 17h.01" /></symbol>
|
||||
<symbol id="i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></symbol>
|
||||
<symbol id="i-server" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2" /> <rect width="20" height="8" x="2" y="14" rx="2" ry="2" /> <line x1="6" x2="6.01" y1="6" y2="6" /> <line x1="6" x2="6.01" y1="18" y2="18" /></symbol>
|
||||
<symbol id="i-settings" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /> <circle cx="12" cy="12" r="3" /></symbol>
|
||||
<symbol id="i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18" /> <path d="m6 6 12 12" /></symbol>
|
||||
<symbol id="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 16v-4" /> <path d="M12 8h.01" /></symbol>
|
||||
<symbol id="i-hard-drive" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 16h.01" /> <path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" /> <path d="M21.946 12.013H2.054" /> <path d="M6 16h.01" /></symbol>
|
||||
<symbol id="i-cpu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20v2" /> <path d="M12 2v2" /> <path d="M17 20v2" /> <path d="M17 2v2" /> <path d="M2 12h2" /> <path d="M2 17h2" /> <path d="M2 7h2" /> <path d="M20 12h2" /> <path d="M20 17h2" /> <path d="M20 7h2" /> <path d="M7 20v2" /> <path d="M7 2v2" /> <rect x="4" y="4" width="16" height="16" rx="2" /> <rect x="8" y="8" width="8" height="8" rx="1" /></symbol>
|
||||
<symbol id="i-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 6v6l4 2" /></symbol>
|
||||
<symbol id="i-boxes" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /> <path d="m7 16.5-4.74-2.85" /> <path d="m7 16.5 5-3" /> <path d="M7 16.5v5.17" /> <path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /> <path d="m17 16.5-5-3" /> <path d="m17 16.5 4.74-2.85" /> <path d="M17 16.5v5.17" /> <path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" /> <path d="M12 8 7.26 5.15" /> <path d="m12 8 4.74-2.85" /> <path d="M12 13.5V8" /></symbol>
|
||||
<symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /> <path d="M16 3.128a4 4 0 0 1 0 7.744" /> <path d="M22 21v-2a4 4 0 0 0-3-3.87" /> <circle cx="9" cy="7" r="4" /></symbol>
|
||||
</svg>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Felhom <span>Hub</span></h1>
|
||||
<nav class="nav-links">
|
||||
<a href="/" class="nav-link">Dashboard</a>
|
||||
<a href="/configs" class="nav-link">Customers</a>
|
||||
<a href="/apps" class="nav-link">Apps</a>
|
||||
<a href="/hosts" class="nav-link">Hosts</a>
|
||||
<a href="/offsite" class="nav-link">Offsite</a>
|
||||
<a href="/configuration" class="nav-link active">Configuration</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<h2 style="margin-bottom: 1rem;">Configuration</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Managed updates — global floor</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The minimum controller version every box auto-updates to (unless a per-customer override is set).
|
||||
<strong>Saving takes effect immediately</strong> — boxes below the floor update on their next
|
||||
report, no customer action. Blank = no global floor. This setting is independent of the Day-0
|
||||
artifact manifest below.
|
||||
</p>
|
||||
|
||||
<p style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
Effective floor:
|
||||
<code>v0.229.0</code>
|
||||
|
||||
<span style="color: #cbd5e1;">— source: <strong>DB (hub_settings)</strong>; env fallback would be <code>v0.120.0</code></span>
|
||||
|
||||
</p>
|
||||
<form id="global-floor-form" method="POST" action="/configuration/global-floor" style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="text" id="global-floor-input" name="min_controller_version" value="0.229.0" placeholder="e.g. 0.86.0 (blank = clear DB override)" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="confirmGlobalFloor()">Save global floor…</button>
|
||||
<span style="font-size: 0.85em; color: #cbd5e1;">DB override: <code>v0.229.0</code></span>
|
||||
</form>
|
||||
<div id="global-floor-confirm" style="display: none; margin-top: 0.75rem; padding: 0.75rem; border: 1px solid #7c3f00; background: #241a0a; border-radius: 6px; max-width: 44em;">
|
||||
<p id="global-floor-impact" style="margin: 0 0 0.5rem; font-size: 0.9em;">…</p>
|
||||
<p style="margin: 0 0 0.5rem; font-size: 0.85em; color: #cbd5e1;">Type the version again to confirm (or <code>CLEAR</code> to remove the DB override):</p>
|
||||
<input type="text" id="global-floor-confirm-input" placeholder="retype the version…" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="submitGlobalFloor()">Confirm & apply</button>
|
||||
<button class="btn btn-sm btn-ghost" type="button" onclick="document.getElementById('global-floor-confirm').style.display='none';">Cancel</button>
|
||||
<p id="global-floor-confirm-err" style="margin: 0.4em 0 0; font-size: 0.8em; color: #f87171;"></p>
|
||||
</div>
|
||||
<script>
|
||||
function confirmGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var box = document.getElementById('global-floor-confirm');
|
||||
var impact = document.getElementById('global-floor-impact');
|
||||
document.getElementById('global-floor-confirm-input').value = '';
|
||||
document.getElementById('global-floor-confirm-err').textContent = '';
|
||||
box.style.display = 'block';
|
||||
if (v === '') {
|
||||
impact.textContent = 'This will CLEAR the DB floor override (the box falls back to the env default). Type CLEAR to confirm.';
|
||||
return;
|
||||
}
|
||||
impact.textContent = 'Checking blast radius…';
|
||||
fetch('/configuration/global-floor/impact?v=' + encodeURIComponent(v))
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d){
|
||||
if (!d.valid) { impact.textContent = 'Invalid version — use X.Y.Z.'; return; }
|
||||
impact.textContent = 'Saving the minimum version v' + d.version +
|
||||
' takes effect immediately — currently ' + d.below +
|
||||
' box(es) are below this version and would update on their next report.';
|
||||
})
|
||||
.catch(function(){ impact.textContent = 'Could not compute the blast radius; proceed with caution.'; });
|
||||
}
|
||||
function submitGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var typed = document.getElementById('global-floor-confirm-input').value.trim();
|
||||
var err = document.getElementById('global-floor-confirm-err');
|
||||
var expected = (v === '') ? 'CLEAR' : v;
|
||||
if (typed !== expected) { err.textContent = 'Confirmation does not match (' + expected + ').'; return; }
|
||||
document.getElementById('global-floor-form').submit();
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Day-0 artifacts — agent & golden</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The current agent binary + golden archive the host-bootstrap script fetches from Gitea and
|
||||
verifies (sha256) before installing. The hub vouches for these checksums (a different trust
|
||||
root than Gitea). Pick a version — the sha256 is read from Gitea automatically (no manual
|
||||
copy). Choose <em>— none —</em> to clear an artifact.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/artifacts" style="display: grid; grid-template-columns: auto 12em 1fr; gap: 0.5rem; align-items: center; max-width: 56em;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Agent</label>
|
||||
|
||||
<select name="agent_version" id="agent_version" onchange="syncArtifactSha('agent')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.130.0" data-sha="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" selected>0.130.0</option>
|
||||
|
||||
<option value="0.129.0" data-sha="53a54f0620afbd6d4a1b86607e2a84dfbe7a290f44ed38a9485d6d971eecde8d" >0.129.0</option>
|
||||
|
||||
<option value="0.128.0" data-sha="c6eba73bf9b9ad6980cfef57bfb3db31581abc9d643de2ff50d4254576fc1a59" >0.128.0</option>
|
||||
|
||||
<option value="0.127.0" data-sha="f0d2c89311f03fd2b9ab6ae242e09a724ff8ea1fd2214759bae247c5db7dbf72" >0.127.0</option>
|
||||
|
||||
<option value="0.126.0" data-sha="7ecf8e9cdba237bc2d81003440095eace6418d00c3a485f3ca77742a25e4a93b" >0.126.0</option>
|
||||
|
||||
<option value="0.125.0" data-sha="f7d8339b53d92a6c45be7eaf189469a041b6b00b758a64511c0479beae7016b3" >0.125.0</option>
|
||||
|
||||
<option value="0.124.1" data-sha="5c279bda64cdec8cbd76f8a800bcd602063bb17175f406b225775e7dece3a21c" >0.124.1</option>
|
||||
|
||||
<option value="0.124.0" data-sha="5e4179383bc838a7ad360efcfab5e8f02a2939ed8bcc4bc68ffd85ba02a5c9a4" >0.124.0</option>
|
||||
|
||||
<option value="0.123.0" data-sha="74910135ac4feb1b7f0ad4dbd1541d965cbc0fe70d4f47b62ebf7e4bfb962453" >0.123.0</option>
|
||||
|
||||
<option value="0.122.0" data-sha="d5f294e56c1ef59055e8e87fb9135aa477632dbbc56a5d4bff46bbd0466c1edf" >0.122.0</option>
|
||||
|
||||
<option value="0.121.1" data-sha="afaeeb509d1ed70d6e6bebac0393a3cd5be59d51e3db9ff96ef8524bd78546d7" >0.121.1</option>
|
||||
|
||||
<option value="0.121.0" data-sha="b2128f3cd4539225a2842f541f56ffaf5390b1d97f3f3a80076ec5f53dbc7d7a" >0.121.0</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="agent_sha256" id="agent_sha256" value="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Golden</label>
|
||||
|
||||
<select name="golden_version" id="golden_version" onchange="syncArtifactSha('golden')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.229.0" data-sha="39aa886df77b21757aef3b298a389343dc0df5134bb0f14e8f92a451d7bdae87" selected>0.229.0</option>
|
||||
|
||||
<option value="0.228.0" data-sha="76a3a98b9e7cc23bf8ae51b38a6272f576df285cb34cd22235ac3f06a31e53ec" >0.228.0</option>
|
||||
|
||||
<option value="0.227.1" data-sha="66754491dc9bd0130ef8ded9562f63c53a5ffdcfd91baa551141e55fa083ea32" >0.227.1</option>
|
||||
|
||||
<option value="0.226.1" data-sha="70ed8e9377dec22a9b493e55f222b0e25a49d7f3caec8c506e0412fd6baefe69" >0.226.1</option>
|
||||
|
||||
<option value="0.223.0" data-sha="9eaf39ac39219b42ec9e6cbf890275febcdcc6f53325fe0c0f591d3431044f17" >0.223.0</option>
|
||||
|
||||
<option value="0.222.0" data-sha="19f5904f53792684f046ec0bc25426645cb87ad73d5cfc6c03639d9f82706037" >0.222.0</option>
|
||||
|
||||
<option value="0.221.1" data-sha="1c8bf6cf08cadabeca6331f38360d905e867c235067cd10c2716915b6e6df089" >0.221.1</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="golden_sha256" id="golden_sha256" value="39aa886df77b21757aef3b298a389343dc0df5134bb0f14e8f92a451d7bdae87" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Min agent</label>
|
||||
<input type="text" name="min_agent" value="0.129.0" placeholder="e.g. 0.81.0 (blank = uncoupled)" style="padding: 0.3em 0.5em;">
|
||||
<span style="font-size: 0.8em; color: #94a6bf;">The golden's controller CHANGELOG <code>MinAgent:</code>. The hub HOLDS the floor for any box whose agent is below this — blank = uncoupled release, no gating.</span>
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">PBS wrapper</label>
|
||||
<input type="text" name="wrapper_sha256" value="104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3" placeholder="64-hex sha256 (blank = not vouched)" style="grid-column: 2 / 4; padding: 0.3em 0.5em; font-family: monospace;">
|
||||
<span></span>
|
||||
<span style="grid-column: 2 / 4; font-size: 0.8em; color: #94a6bf;">sha256 of <code>configs/felhom-pbs-apply</code> (R-50b). Unlike the agent and golden this root-owned wrapper is installed from <code>raw/branch/main</code> — unversioned and unpinned. Recording it here does not fix the channel; it makes host drift <em>visible</em>: agents report the installed file's hash and a mismatch is surfaced on the host page.</span>
|
||||
<span></span><span></span>
|
||||
<button class="btn btn-sm" type="submit" style="justify-self: start;">Save artifact manifest</button>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function syncArtifactSha(kind) {
|
||||
var sel = document.getElementById(kind + '_version');
|
||||
var sha = document.getElementById(kind + '_sha256');
|
||||
if (!sel || !sha) return;
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
sha.value = (opt && opt.getAttribute('data-sha')) || '';
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Login password</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The password for signing in to this hub UI. <strong>Changing it takes effect immediately</strong>
|
||||
for the next sign-in — your current session stays logged in. Enter your current password to confirm.
|
||||
If you ever lose it, the deployment ConfigMap (<code>auth.password_hash</code>) remains the reset path.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/password" style="display: grid; grid-template-columns: auto 20em; gap: 0.5rem; align-items: center; max-width: 40em;"
|
||||
onsubmit="return felhomCheckNewPw(this);">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Current password</label>
|
||||
<input type="password" name="current_password" autocomplete="current-password" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">New password</label>
|
||||
<input type="password" id="new_password" name="new_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Confirm new password</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="btn btn-sm" type="submit">Change password</button>
|
||||
<span id="pw-client-err" style="margin-left: 0.6em; font-size: 0.8em; color: #f87171;"></span>
|
||||
</span>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function felhomCheckNewPw(form) {
|
||||
var a = form.new_password.value;
|
||||
var b = form.confirm_password.value;
|
||||
var err = document.getElementById('pw-client-err');
|
||||
err.textContent = '';
|
||||
if (a.length < 8) { err.textContent = 'New password must be at least 8 characters.'; return false; }
|
||||
if (a !== b) { err.textContent = 'New password and confirmation do not match.'; return false; }
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Assets</h3>
|
||||
<p class="text-muted" style="margin-bottom: 1rem;">
|
||||
App logos and screenshots served to controllers. Assets are seeded from the Docker image
|
||||
and synced to controllers daily via the asset manifest API.
|
||||
</p>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="label">Files in manifest</span>
|
||||
<span class="value">211</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">Manifest generated</span>
|
||||
<span class="value" style="font-family: var(--font-mono); font-size: 0.85em;">2026-08-30T16:51:40Z</span>
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/configuration" style="margin-top: 1rem;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="hidden" name="action" value="refresh_assets">
|
||||
<button type="submit" class="btn" onclick="this.disabled=true;this.textContent='Refreshing…';this.form.submit();">Refresh Assets from Image</button>
|
||||
</form>
|
||||
<p class="text-muted" style="margin-top: 0.75rem; font-size: 0.8rem;">
|
||||
Re-reads the baked-in asset seed directory and updates changed files.
|
||||
Controllers will pick up changes on their next daily sync or manual trigger.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<footer style="margin-top: 2rem; color: var(--text-muted); font-size: 0.8rem; text-align: center;">
|
||||
Felhom Hub <span style="font-family: var(--font-mono)">0.109.0</span>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
=== preconditions ===
|
||||
2026-08-31T14:09:11Z
|
||||
controller image 0.230.0 in registry: HTTP 200
|
||||
MinAgent (CHANGELOG v0.230.0): 0.129.0
|
||||
hub BEFORE: golden=0.229.0 agent=0.130.0 min_agent=0.129.0
|
||||
newest published golden: 0.229.0
|
||||
/dev/sda1 9.1T 3.1T 5.5T 37% /mnt/5_hdd
|
||||
/dev/sdb1 445G 216G 207G 51% /
|
||||
revert rc=0 (also proves no qemu holds the qcow2)
|
||||
@@ -0,0 +1,44 @@
|
||||
Warning: Permanently added '[localhost]:2222' (ED25519) to the list of known hosts.
|
||||
=== pveam update (the virgin snapshot INDEX is stale too) ===
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = "UTF-8",
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
|
||||
update successful
|
||||
=== available debian-13 ===
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = "UTF-8",
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
|
||||
system debian-13-standard_13.6-1_amd64.tar.zst
|
||||
system debian-13-standard_13.6-1_arm64.tar.zst
|
||||
@@ -0,0 +1,8 @@
|
||||
65536K ........ ........ ........ ........ 77% 8.84M 3s
|
||||
98304K ........ ........ ........ ... 100% 11.2M=12s
|
||||
2026-08-31 16:10:24 (9.98 MB/s) - '/var/lib/vz/template/cache/debian-13-standard_13.6-1_amd64.tar.zst.tmp_dwnl.1223' saved [129954319/129954319]
|
||||
calculating checksum...OK, checksum verified
|
||||
download of 'http://download.proxmox.com/images/system/debian-13-standard_13.6-1_amd64.tar.zst' to '/var/lib/vz/template/cache/debian-13-standard_13.6-1_amd64.tar.zst' finished
|
||||
=== templates present ===
|
||||
NAME SIZE
|
||||
local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst 123.93MB
|
||||
@@ -0,0 +1,4 @@
|
||||
-rw------- 1 root root 41 Aug 31 16:10 /root/.gitea-token
|
||||
-rwx------ 1 root root 30373 Aug 31 16:10 /root/build-golden.sh
|
||||
script version: GOLDEN_SCRIPT_VERSION="3.0.0"
|
||||
token bytes: 41 (value never printed)
|
||||
@@ -0,0 +1,6 @@
|
||||
Running as unit: golden-bake.service; invocation ID: d9094d8ab9c2481a8e337afa5121e25d
|
||||
=== token-leak check on the unit properties (must be 0) ===
|
||||
0
|
||||
=== positive control that the grep WORKS (must be 1) ===
|
||||
1
|
||||
active
|
||||
@@ -0,0 +1,322 @@
|
||||
[golden] build-golden.sh v3.0.0 — baking controller gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
[golden] creating build LXC 9100 (nesting=1,keyctl=1, unprivileged; rootfs 32G + ONE data volume 24G @ /var/lib/felhom, backup=1) …
|
||||
Logical volume "vm-9100-disk-0" created.
|
||||
Logical volume pve/vm-9100-disk-0 changed.
|
||||
Creating filesystem with 8388608 4k blocks and 2097152 inodes
|
||||
Filesystem UUID: 6570f8d5-8322-44b9-a8d7-6c7bca23ed01
|
||||
Superblock backups stored on blocks:
|
||||
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
|
||||
4096000, 7962624
|
||||
Logical volume "vm-9100-disk-1" created.
|
||||
Logical volume pve/vm-9100-disk-1 changed.
|
||||
Creating filesystem with 6291456 4k blocks and 1572864 inodes
|
||||
Filesystem UUID: df74688f-5799-4023-a704-5f4b14420724
|
||||
Superblock backups stored on blocks:
|
||||
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
|
||||
extracting archive '/var/lib/vz/template/cache/debian-13-standard_13.6-1_amd64.tar.zst'
|
||||
Total bytes read: 553512960 (528MiB, 107MiB/s)
|
||||
Detected container architecture: amd64
|
||||
Creating SSH host key 'ssh_host_rsa_key' - this may take some time ...
|
||||
done: SHA256:wTmy+E+RiSYEvFoekpADhdBpm+/2LBnQDCQOnmMfgoA root@felhom-golden
|
||||
Creating SSH host key 'ssh_host_ecdsa_key' - this may take some time ...
|
||||
done: SHA256:iJkyqbDKh1UwnLgYXubhMGIym2GNsfsjT75R3RgKdQI root@felhom-golden
|
||||
Creating SSH host key 'ssh_host_ed25519_key' - this may take some time ...
|
||||
done: SHA256:t09l63iIyQtdG8HN/lbqwmfKZ2r4pQI6lHgOWW2wIME root@felhom-golden
|
||||
[golden] starting + installing Docker (official repo, trixie channel) …
|
||||
apt-listchanges: Can't set locale; make sure $LC_* and $LANG are correct!
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = (unset),
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to the standard locale ("C").
|
||||
apt-listchanges: Can't set locale; make sure $LC_* and $LANG are correct!
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = (unset),
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to the standard locale ("C").
|
||||
[golden] baking daemon.json: classic overlay2 driver (containerd-snapshotter OFF) + log rotation …
|
||||
[golden] wiring the single data volume (R-165 variant V-c): /var/lib/felhom/{docker,sys_drive} -> binds …
|
||||
[golden] verifying Docker works in the build guest (storage driver should be overlay2 on the ext4 data volume) …
|
||||
Unable to find image 'hello-world:latest' locally
|
||||
latest: Pulling from library/hello-world
|
||||
4f55086f7dd0: Pulling fs layer
|
||||
4f55086f7dd0: Verifying Checksum
|
||||
4f55086f7dd0: Download complete
|
||||
4f55086f7dd0: Pull complete
|
||||
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
|
||||
Status: Downloaded newer image for hello-world:latest
|
||||
docker OK (overlay2; data-root /var/lib/docker)
|
||||
/var/lib/docker is a real mount: /dev/mapper/pve-vm--9100--disk--1[/docker] ext4
|
||||
/mnt/sys_drive is a real mount: /dev/mapper/pve-vm--9100--disk--1[/sys_drive] ext4
|
||||
both paths are ONE filesystem: /dev/mapper/pve-vm--9100--disk--1 23317576
|
||||
[golden] baking the in-guest controller image gitea.dooplex.hu/admin/felhom-controller:0.230.0 (no registry cred at deploy) …
|
||||
|
||||
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
|
||||
Configure a credential helper to remove this warning. See
|
||||
https://docs.docker.com/go/credential-store/
|
||||
|
||||
0.230.0: Pulling from admin/felhom-controller
|
||||
a8ac7f6c67ab: Pulling fs layer
|
||||
bf30769d36e7: Pulling fs layer
|
||||
044b66fbe46c: Pulling fs layer
|
||||
b5c41a28e83f: Pulling fs layer
|
||||
21d94e6c63f0: Pulling fs layer
|
||||
23c8544b7435: Pulling fs layer
|
||||
b5c41a28e83f: Waiting
|
||||
21d94e6c63f0: Waiting
|
||||
23c8544b7435: Waiting
|
||||
a8ac7f6c67ab: Verifying Checksum
|
||||
a8ac7f6c67ab: Download complete
|
||||
b5c41a28e83f: Download complete
|
||||
21d94e6c63f0: Verifying Checksum
|
||||
21d94e6c63f0: Download complete
|
||||
23c8544b7435: Verifying Checksum
|
||||
23c8544b7435: Download complete
|
||||
044b66fbe46c: Verifying Checksum
|
||||
044b66fbe46c: Download complete
|
||||
bf30769d36e7: Verifying Checksum
|
||||
bf30769d36e7: Download complete
|
||||
a8ac7f6c67ab: Pull complete
|
||||
bf30769d36e7: Pull complete
|
||||
044b66fbe46c: Pull complete
|
||||
b5c41a28e83f: Pull complete
|
||||
21d94e6c63f0: Pull complete
|
||||
23c8544b7435: Pull complete
|
||||
Digest: sha256:50659db2900c615ca13c72eaa8c5e88a8f9a76b808a7b29721f818ec7b2fefb7
|
||||
Status: Downloaded newer image for gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
[golden] asking the controller which infra images it manages …
|
||||
[golden] baking infra images (4): traefik:v3.6.7 cloudflare/cloudflared:2026.6.0 gtstef/filebrowser:1.3.3-stable gitea.dooplex.hu/admin/felhom-samba:1.1.0 …
|
||||
v3.6.7: Pulling from library/traefik
|
||||
589002ba0eae: Pulling fs layer
|
||||
ef63511ea6cc: Pulling fs layer
|
||||
0738e5cb835e: Pulling fs layer
|
||||
3e6813f70c64: Pulling fs layer
|
||||
3e6813f70c64: Waiting
|
||||
589002ba0eae: Verifying Checksum
|
||||
589002ba0eae: Download complete
|
||||
ef63511ea6cc: Verifying Checksum
|
||||
ef63511ea6cc: Download complete
|
||||
3e6813f70c64: Verifying Checksum
|
||||
3e6813f70c64: Download complete
|
||||
0738e5cb835e: Verifying Checksum
|
||||
0738e5cb835e: Download complete
|
||||
589002ba0eae: Pull complete
|
||||
ef63511ea6cc: Pull complete
|
||||
0738e5cb835e: Pull complete
|
||||
3e6813f70c64: Pull complete
|
||||
Digest: sha256:a9890c898f379c1905ee5b28342f6b408dc863f08db2dab20e46c267d1ff463a
|
||||
Status: Downloaded newer image for traefik:v3.6.7
|
||||
docker.io/library/traefik:v3.6.7
|
||||
2026.6.0: Pulling from cloudflare/cloudflared
|
||||
47de5dd0b812: Pulling fs layer
|
||||
c172f21841df: Pulling fs layer
|
||||
99515e7b4d35: Pulling fs layer
|
||||
99ba982a9142: Pulling fs layer
|
||||
d6b1b89eccac: Pulling fs layer
|
||||
2780920e5dbf: Pulling fs layer
|
||||
7c12895b777b: Pulling fs layer
|
||||
3214acf345c0: Pulling fs layer
|
||||
52630fc75a18: Pulling fs layer
|
||||
dd64bf2dd177: Pulling fs layer
|
||||
b839dfae01f6: Pulling fs layer
|
||||
ebddc55facdc: Pulling fs layer
|
||||
bdfd7f7e5bf6: Pulling fs layer
|
||||
2d4d7adf6272: Pulling fs layer
|
||||
40008157d8d2: Pulling fs layer
|
||||
bd8962e29291: Pulling fs layer
|
||||
cac2ae0193cb: Pulling fs layer
|
||||
74d1dac84ecc: Pulling fs layer
|
||||
dd64bf2dd177: Waiting
|
||||
b839dfae01f6: Waiting
|
||||
ebddc55facdc: Waiting
|
||||
bdfd7f7e5bf6: Waiting
|
||||
2d4d7adf6272: Waiting
|
||||
40008157d8d2: Waiting
|
||||
bd8962e29291: Waiting
|
||||
cac2ae0193cb: Waiting
|
||||
74d1dac84ecc: Waiting
|
||||
99ba982a9142: Waiting
|
||||
d6b1b89eccac: Waiting
|
||||
2780920e5dbf: Waiting
|
||||
7c12895b777b: Waiting
|
||||
3214acf345c0: Waiting
|
||||
52630fc75a18: Waiting
|
||||
47de5dd0b812: Verifying Checksum
|
||||
47de5dd0b812: Download complete
|
||||
c172f21841df: Verifying Checksum
|
||||
c172f21841df: Download complete
|
||||
99515e7b4d35: Verifying Checksum
|
||||
99515e7b4d35: Download complete
|
||||
99ba982a9142: Verifying Checksum
|
||||
99ba982a9142: Download complete
|
||||
47de5dd0b812: Pull complete
|
||||
d6b1b89eccac: Verifying Checksum
|
||||
d6b1b89eccac: Download complete
|
||||
2780920e5dbf: Verifying Checksum
|
||||
2780920e5dbf: Download complete
|
||||
7c12895b777b: Verifying Checksum
|
||||
7c12895b777b: Download complete
|
||||
3214acf345c0: Verifying Checksum
|
||||
3214acf345c0: Download complete
|
||||
52630fc75a18: Verifying Checksum
|
||||
52630fc75a18: Download complete
|
||||
dd64bf2dd177: Verifying Checksum
|
||||
dd64bf2dd177: Download complete
|
||||
b839dfae01f6: Verifying Checksum
|
||||
b839dfae01f6: Download complete
|
||||
ebddc55facdc: Verifying Checksum
|
||||
ebddc55facdc: Download complete
|
||||
bdfd7f7e5bf6: Verifying Checksum
|
||||
bdfd7f7e5bf6: Download complete
|
||||
c172f21841df: Pull complete
|
||||
40008157d8d2: Verifying Checksum
|
||||
40008157d8d2: Download complete
|
||||
bd8962e29291: Verifying Checksum
|
||||
bd8962e29291: Download complete
|
||||
2d4d7adf6272: Verifying Checksum
|
||||
2d4d7adf6272: Download complete
|
||||
cac2ae0193cb: Verifying Checksum
|
||||
cac2ae0193cb: Download complete
|
||||
74d1dac84ecc: Verifying Checksum
|
||||
74d1dac84ecc: Download complete
|
||||
99515e7b4d35: Pull complete
|
||||
99ba982a9142: Pull complete
|
||||
d6b1b89eccac: Pull complete
|
||||
2780920e5dbf: Pull complete
|
||||
7c12895b777b: Pull complete
|
||||
3214acf345c0: Pull complete
|
||||
52630fc75a18: Pull complete
|
||||
dd64bf2dd177: Pull complete
|
||||
b839dfae01f6: Pull complete
|
||||
ebddc55facdc: Pull complete
|
||||
bdfd7f7e5bf6: Pull complete
|
||||
2d4d7adf6272: Pull complete
|
||||
40008157d8d2: Pull complete
|
||||
bd8962e29291: Pull complete
|
||||
cac2ae0193cb: Pull complete
|
||||
74d1dac84ecc: Pull complete
|
||||
Digest: sha256:ba461b8aa9c042156dbd39c38657fe7431bafa063220eab8d5330a523863da9f
|
||||
Status: Downloaded newer image for cloudflare/cloudflared:2026.6.0
|
||||
docker.io/cloudflare/cloudflared:2026.6.0
|
||||
1.3.3-stable: Pulling from gtstef/filebrowser
|
||||
6a0ac1617861: Pulling fs layer
|
||||
ef8806083e82: Pulling fs layer
|
||||
b74107c861c7: Pulling fs layer
|
||||
adc935def003: Pulling fs layer
|
||||
4f4fb700ef54: Pulling fs layer
|
||||
18695ccc900a: Pulling fs layer
|
||||
45d119d5c397: Pulling fs layer
|
||||
dac52db4fc51: Pulling fs layer
|
||||
6d598f86b2f2: Pulling fs layer
|
||||
8aa349c8396c: Pulling fs layer
|
||||
45d119d5c397: Waiting
|
||||
dac52db4fc51: Waiting
|
||||
6d598f86b2f2: Waiting
|
||||
8aa349c8396c: Waiting
|
||||
adc935def003: Waiting
|
||||
4f4fb700ef54: Waiting
|
||||
18695ccc900a: Waiting
|
||||
6a0ac1617861: Verifying Checksum
|
||||
6a0ac1617861: Download complete
|
||||
adc935def003: Verifying Checksum
|
||||
adc935def003: Download complete
|
||||
4f4fb700ef54: Verifying Checksum
|
||||
4f4fb700ef54: Download complete
|
||||
b74107c861c7: Verifying Checksum
|
||||
b74107c861c7: Download complete
|
||||
6a0ac1617861: Pull complete
|
||||
45d119d5c397: Verifying Checksum
|
||||
45d119d5c397: Download complete
|
||||
ef8806083e82: Verifying Checksum
|
||||
ef8806083e82: Download complete
|
||||
6d598f86b2f2: Verifying Checksum
|
||||
6d598f86b2f2: Download complete
|
||||
dac52db4fc51: Verifying Checksum
|
||||
dac52db4fc51: Download complete
|
||||
8aa349c8396c: Verifying Checksum
|
||||
8aa349c8396c: Download complete
|
||||
18695ccc900a: Verifying Checksum
|
||||
18695ccc900a: Download complete
|
||||
ef8806083e82: Pull complete
|
||||
b74107c861c7: Pull complete
|
||||
adc935def003: Pull complete
|
||||
4f4fb700ef54: Pull complete
|
||||
18695ccc900a: Pull complete
|
||||
45d119d5c397: Pull complete
|
||||
dac52db4fc51: Pull complete
|
||||
6d598f86b2f2: Pull complete
|
||||
8aa349c8396c: Pull complete
|
||||
Digest: sha256:eb3733681db8757412632c61a99ad656f0d94ed6781bb2ea114b4d70babab78c
|
||||
Status: Downloaded newer image for gtstef/filebrowser:1.3.3-stable
|
||||
docker.io/gtstef/filebrowser:1.3.3-stable
|
||||
1.1.0: Pulling from admin/felhom-samba
|
||||
897d797d2723: Pulling fs layer
|
||||
3051591aa250: Pulling fs layer
|
||||
ce57a3f93416: Pulling fs layer
|
||||
fb94eeec2fe1: Pulling fs layer
|
||||
fb94eeec2fe1: Waiting
|
||||
ce57a3f93416: Verifying Checksum
|
||||
ce57a3f93416: Download complete
|
||||
fb94eeec2fe1: Verifying Checksum
|
||||
fb94eeec2fe1: Download complete
|
||||
897d797d2723: Verifying Checksum
|
||||
897d797d2723: Download complete
|
||||
3051591aa250: Verifying Checksum
|
||||
3051591aa250: Download complete
|
||||
897d797d2723: Pull complete
|
||||
3051591aa250: Pull complete
|
||||
ce57a3f93416: Pull complete
|
||||
fb94eeec2fe1: Pull complete
|
||||
Digest: sha256:1c17c09422bec0366d7cf0e0fcfc1486ba6c90334a0a5d5c851073a9342f8f10
|
||||
Status: Downloaded newer image for gitea.dooplex.hu/admin/felhom-samba:1.1.0
|
||||
gitea.dooplex.hu/admin/felhom-samba:1.1.0
|
||||
[golden] baking the controller-bootstrap unit (deploys the BAKED controller from the config mount) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-controller-bootstrap.service' → '/etc/systemd/system/felhom-controller-bootstrap.service'.
|
||||
[golden] baking the controller-bootstrap PATH unit (starts the service on bootstrap-mount hot-plug — B1) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-controller-bootstrap.path' → '/etc/systemd/system/felhom-controller-bootstrap.path'.
|
||||
[golden] baking the first-boot SSH host-key regeneration unit (F3) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-regen-hostkeys.service' → '/etc/systemd/system/felhom-regen-hostkeys.service'.
|
||||
[golden] identity-clean + minimize …
|
||||
[golden] stop + archive …
|
||||
INFO: including mount point rootfs ('/') in backup
|
||||
INFO: including mount point mp0 ('/var/lib/felhom') in backup
|
||||
INFO: archive file size: 627MB
|
||||
INFO: Finished Backup of VM 9100 (00:00:41)
|
||||
[golden] DONE. golden archive volid: local:backup/vzdump-lxc-9100-2026_08_31-16_15_14.tar.zst (rootfs 32G + ONE data volume 24G @ /var/lib/felhom, all in the archive)
|
||||
[golden] publishing golden (657873700 bytes, sha256 9287f7cef5f13166…) → https://gitea.dooplex.hu/api/packages/admin/generic/felhom-golden/0.230.0/golden.tar.zst
|
||||
[golden] pre-delete existing: HTTP 404 (404/204 expected)
|
||||
[golden] upload OK (HTTP 201)
|
||||
GOLDEN_VERSION=0.230.0
|
||||
GOLDEN_SHA256=9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
[golden] Record in the hub operator UI (Configs → Day-0 artifacts): golden 0.230.0 / 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
[golden] (the build guest 9100 is stopped; destroy it with: pct destroy 9100 --purge)
|
||||
@@ -0,0 +1,328 @@
|
||||
[golden] build-golden.sh v3.0.0 — baking controller gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
[golden] creating build LXC 9100 (nesting=1,keyctl=1, unprivileged; rootfs 32G + ONE data volume 24G @ /var/lib/felhom, backup=1) …
|
||||
Logical volume "vm-9100-disk-0" created.
|
||||
Logical volume pve/vm-9100-disk-0 changed.
|
||||
Creating filesystem with 8388608 4k blocks and 2097152 inodes
|
||||
Filesystem UUID: 6570f8d5-8322-44b9-a8d7-6c7bca23ed01
|
||||
Superblock backups stored on blocks:
|
||||
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
|
||||
4096000, 7962624
|
||||
Logical volume "vm-9100-disk-1" created.
|
||||
Logical volume pve/vm-9100-disk-1 changed.
|
||||
Creating filesystem with 6291456 4k blocks and 1572864 inodes
|
||||
Filesystem UUID: df74688f-5799-4023-a704-5f4b14420724
|
||||
Superblock backups stored on blocks:
|
||||
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
|
||||
extracting archive '/var/lib/vz/template/cache/debian-13-standard_13.6-1_amd64.tar.zst'
|
||||
Total bytes read: 553512960 (528MiB, 107MiB/s)
|
||||
Detected container architecture: amd64
|
||||
Creating SSH host key 'ssh_host_rsa_key' - this may take some time ...
|
||||
done: SHA256:wTmy+E+RiSYEvFoekpADhdBpm+/2LBnQDCQOnmMfgoA root@felhom-golden
|
||||
Creating SSH host key 'ssh_host_ecdsa_key' - this may take some time ...
|
||||
done: SHA256:iJkyqbDKh1UwnLgYXubhMGIym2GNsfsjT75R3RgKdQI root@felhom-golden
|
||||
Creating SSH host key 'ssh_host_ed25519_key' - this may take some time ...
|
||||
done: SHA256:t09l63iIyQtdG8HN/lbqwmfKZ2r4pQI6lHgOWW2wIME root@felhom-golden
|
||||
[golden] starting + installing Docker (official repo, trixie channel) …
|
||||
apt-listchanges: Can't set locale; make sure $LC_* and $LANG are correct!
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = (unset),
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to the standard locale ("C").
|
||||
locale: Cannot set LC_CTYPE to default locale: No such file or directory
|
||||
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
|
||||
locale: Cannot set LC_ALL to default locale: No such file or directory
|
||||
apt-listchanges: Can't set locale; make sure $LC_* and $LANG are correct!
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = (unset),
|
||||
LC_NUMERIC = (unset),
|
||||
LC_COLLATE = (unset),
|
||||
LC_TIME = (unset),
|
||||
LC_MESSAGES = (unset),
|
||||
LC_MONETARY = (unset),
|
||||
LC_ADDRESS = (unset),
|
||||
LC_IDENTIFICATION = (unset),
|
||||
LC_MEASUREMENT = (unset),
|
||||
LC_PAPER = (unset),
|
||||
LC_TELEPHONE = (unset),
|
||||
LC_NAME = (unset),
|
||||
LANG = "en_US.UTF-8"
|
||||
are supported and installed on your system.
|
||||
perl: warning: Falling back to the standard locale ("C").
|
||||
locale: Cannot set LC_CTYPE to default locale: No such file or directory
|
||||
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
|
||||
locale: Cannot set LC_ALL to default locale: No such file or directory
|
||||
[golden] baking daemon.json: classic overlay2 driver (containerd-snapshotter OFF) + log rotation …
|
||||
[golden] wiring the single data volume (R-165 variant V-c): /var/lib/felhom/{docker,sys_drive} -> binds …
|
||||
[golden] verifying Docker works in the build guest (storage driver should be overlay2 on the ext4 data volume) …
|
||||
Unable to find image 'hello-world:latest' locally
|
||||
latest: Pulling from library/hello-world
|
||||
4f55086f7dd0: Pulling fs layer
|
||||
4f55086f7dd0: Verifying Checksum
|
||||
4f55086f7dd0: Download complete
|
||||
4f55086f7dd0: Pull complete
|
||||
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
|
||||
Status: Downloaded newer image for hello-world:latest
|
||||
docker OK (overlay2; data-root /var/lib/docker)
|
||||
/var/lib/docker is a real mount: /dev/mapper/pve-vm--9100--disk--1[/docker] ext4
|
||||
/mnt/sys_drive is a real mount: /dev/mapper/pve-vm--9100--disk--1[/sys_drive] ext4
|
||||
both paths are ONE filesystem: /dev/mapper/pve-vm--9100--disk--1 23317576
|
||||
[golden] baking the in-guest controller image gitea.dooplex.hu/admin/felhom-controller:0.230.0 (no registry cred at deploy) …
|
||||
|
||||
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
|
||||
Configure a credential helper to remove this warning. See
|
||||
https://docs.docker.com/go/credential-store/
|
||||
|
||||
0.230.0: Pulling from admin/felhom-controller
|
||||
a8ac7f6c67ab: Pulling fs layer
|
||||
bf30769d36e7: Pulling fs layer
|
||||
044b66fbe46c: Pulling fs layer
|
||||
b5c41a28e83f: Pulling fs layer
|
||||
21d94e6c63f0: Pulling fs layer
|
||||
23c8544b7435: Pulling fs layer
|
||||
b5c41a28e83f: Waiting
|
||||
21d94e6c63f0: Waiting
|
||||
23c8544b7435: Waiting
|
||||
a8ac7f6c67ab: Verifying Checksum
|
||||
a8ac7f6c67ab: Download complete
|
||||
b5c41a28e83f: Download complete
|
||||
21d94e6c63f0: Verifying Checksum
|
||||
21d94e6c63f0: Download complete
|
||||
23c8544b7435: Verifying Checksum
|
||||
23c8544b7435: Download complete
|
||||
044b66fbe46c: Verifying Checksum
|
||||
044b66fbe46c: Download complete
|
||||
bf30769d36e7: Verifying Checksum
|
||||
bf30769d36e7: Download complete
|
||||
a8ac7f6c67ab: Pull complete
|
||||
bf30769d36e7: Pull complete
|
||||
044b66fbe46c: Pull complete
|
||||
b5c41a28e83f: Pull complete
|
||||
21d94e6c63f0: Pull complete
|
||||
23c8544b7435: Pull complete
|
||||
Digest: sha256:50659db2900c615ca13c72eaa8c5e88a8f9a76b808a7b29721f818ec7b2fefb7
|
||||
Status: Downloaded newer image for gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
[golden] asking the controller which infra images it manages …
|
||||
[golden] baking infra images (4): traefik:v3.6.7 cloudflare/cloudflared:2026.6.0 gtstef/filebrowser:1.3.3-stable gitea.dooplex.hu/admin/felhom-samba:1.1.0 …
|
||||
v3.6.7: Pulling from library/traefik
|
||||
589002ba0eae: Pulling fs layer
|
||||
ef63511ea6cc: Pulling fs layer
|
||||
0738e5cb835e: Pulling fs layer
|
||||
3e6813f70c64: Pulling fs layer
|
||||
3e6813f70c64: Waiting
|
||||
589002ba0eae: Verifying Checksum
|
||||
589002ba0eae: Download complete
|
||||
ef63511ea6cc: Verifying Checksum
|
||||
ef63511ea6cc: Download complete
|
||||
3e6813f70c64: Verifying Checksum
|
||||
3e6813f70c64: Download complete
|
||||
0738e5cb835e: Verifying Checksum
|
||||
0738e5cb835e: Download complete
|
||||
589002ba0eae: Pull complete
|
||||
ef63511ea6cc: Pull complete
|
||||
0738e5cb835e: Pull complete
|
||||
3e6813f70c64: Pull complete
|
||||
Digest: sha256:a9890c898f379c1905ee5b28342f6b408dc863f08db2dab20e46c267d1ff463a
|
||||
Status: Downloaded newer image for traefik:v3.6.7
|
||||
docker.io/library/traefik:v3.6.7
|
||||
2026.6.0: Pulling from cloudflare/cloudflared
|
||||
47de5dd0b812: Pulling fs layer
|
||||
c172f21841df: Pulling fs layer
|
||||
99515e7b4d35: Pulling fs layer
|
||||
99ba982a9142: Pulling fs layer
|
||||
d6b1b89eccac: Pulling fs layer
|
||||
2780920e5dbf: Pulling fs layer
|
||||
7c12895b777b: Pulling fs layer
|
||||
3214acf345c0: Pulling fs layer
|
||||
52630fc75a18: Pulling fs layer
|
||||
dd64bf2dd177: Pulling fs layer
|
||||
b839dfae01f6: Pulling fs layer
|
||||
ebddc55facdc: Pulling fs layer
|
||||
bdfd7f7e5bf6: Pulling fs layer
|
||||
2d4d7adf6272: Pulling fs layer
|
||||
40008157d8d2: Pulling fs layer
|
||||
bd8962e29291: Pulling fs layer
|
||||
cac2ae0193cb: Pulling fs layer
|
||||
74d1dac84ecc: Pulling fs layer
|
||||
dd64bf2dd177: Waiting
|
||||
b839dfae01f6: Waiting
|
||||
ebddc55facdc: Waiting
|
||||
bdfd7f7e5bf6: Waiting
|
||||
2d4d7adf6272: Waiting
|
||||
40008157d8d2: Waiting
|
||||
bd8962e29291: Waiting
|
||||
cac2ae0193cb: Waiting
|
||||
74d1dac84ecc: Waiting
|
||||
99ba982a9142: Waiting
|
||||
d6b1b89eccac: Waiting
|
||||
2780920e5dbf: Waiting
|
||||
7c12895b777b: Waiting
|
||||
3214acf345c0: Waiting
|
||||
52630fc75a18: Waiting
|
||||
47de5dd0b812: Verifying Checksum
|
||||
47de5dd0b812: Download complete
|
||||
c172f21841df: Verifying Checksum
|
||||
c172f21841df: Download complete
|
||||
99515e7b4d35: Verifying Checksum
|
||||
99515e7b4d35: Download complete
|
||||
99ba982a9142: Verifying Checksum
|
||||
99ba982a9142: Download complete
|
||||
47de5dd0b812: Pull complete
|
||||
d6b1b89eccac: Verifying Checksum
|
||||
d6b1b89eccac: Download complete
|
||||
2780920e5dbf: Verifying Checksum
|
||||
2780920e5dbf: Download complete
|
||||
7c12895b777b: Verifying Checksum
|
||||
7c12895b777b: Download complete
|
||||
3214acf345c0: Verifying Checksum
|
||||
3214acf345c0: Download complete
|
||||
52630fc75a18: Verifying Checksum
|
||||
52630fc75a18: Download complete
|
||||
dd64bf2dd177: Verifying Checksum
|
||||
dd64bf2dd177: Download complete
|
||||
b839dfae01f6: Verifying Checksum
|
||||
b839dfae01f6: Download complete
|
||||
ebddc55facdc: Verifying Checksum
|
||||
ebddc55facdc: Download complete
|
||||
bdfd7f7e5bf6: Verifying Checksum
|
||||
bdfd7f7e5bf6: Download complete
|
||||
c172f21841df: Pull complete
|
||||
40008157d8d2: Verifying Checksum
|
||||
40008157d8d2: Download complete
|
||||
bd8962e29291: Verifying Checksum
|
||||
bd8962e29291: Download complete
|
||||
2d4d7adf6272: Verifying Checksum
|
||||
2d4d7adf6272: Download complete
|
||||
cac2ae0193cb: Verifying Checksum
|
||||
cac2ae0193cb: Download complete
|
||||
74d1dac84ecc: Verifying Checksum
|
||||
74d1dac84ecc: Download complete
|
||||
99515e7b4d35: Pull complete
|
||||
99ba982a9142: Pull complete
|
||||
d6b1b89eccac: Pull complete
|
||||
2780920e5dbf: Pull complete
|
||||
7c12895b777b: Pull complete
|
||||
3214acf345c0: Pull complete
|
||||
52630fc75a18: Pull complete
|
||||
dd64bf2dd177: Pull complete
|
||||
b839dfae01f6: Pull complete
|
||||
ebddc55facdc: Pull complete
|
||||
bdfd7f7e5bf6: Pull complete
|
||||
2d4d7adf6272: Pull complete
|
||||
40008157d8d2: Pull complete
|
||||
bd8962e29291: Pull complete
|
||||
cac2ae0193cb: Pull complete
|
||||
74d1dac84ecc: Pull complete
|
||||
Digest: sha256:ba461b8aa9c042156dbd39c38657fe7431bafa063220eab8d5330a523863da9f
|
||||
Status: Downloaded newer image for cloudflare/cloudflared:2026.6.0
|
||||
docker.io/cloudflare/cloudflared:2026.6.0
|
||||
1.3.3-stable: Pulling from gtstef/filebrowser
|
||||
6a0ac1617861: Pulling fs layer
|
||||
ef8806083e82: Pulling fs layer
|
||||
b74107c861c7: Pulling fs layer
|
||||
adc935def003: Pulling fs layer
|
||||
4f4fb700ef54: Pulling fs layer
|
||||
18695ccc900a: Pulling fs layer
|
||||
45d119d5c397: Pulling fs layer
|
||||
dac52db4fc51: Pulling fs layer
|
||||
6d598f86b2f2: Pulling fs layer
|
||||
8aa349c8396c: Pulling fs layer
|
||||
45d119d5c397: Waiting
|
||||
dac52db4fc51: Waiting
|
||||
6d598f86b2f2: Waiting
|
||||
8aa349c8396c: Waiting
|
||||
adc935def003: Waiting
|
||||
4f4fb700ef54: Waiting
|
||||
18695ccc900a: Waiting
|
||||
6a0ac1617861: Verifying Checksum
|
||||
6a0ac1617861: Download complete
|
||||
adc935def003: Verifying Checksum
|
||||
adc935def003: Download complete
|
||||
4f4fb700ef54: Verifying Checksum
|
||||
4f4fb700ef54: Download complete
|
||||
b74107c861c7: Verifying Checksum
|
||||
b74107c861c7: Download complete
|
||||
6a0ac1617861: Pull complete
|
||||
45d119d5c397: Verifying Checksum
|
||||
45d119d5c397: Download complete
|
||||
ef8806083e82: Verifying Checksum
|
||||
ef8806083e82: Download complete
|
||||
6d598f86b2f2: Verifying Checksum
|
||||
6d598f86b2f2: Download complete
|
||||
dac52db4fc51: Verifying Checksum
|
||||
dac52db4fc51: Download complete
|
||||
8aa349c8396c: Verifying Checksum
|
||||
8aa349c8396c: Download complete
|
||||
18695ccc900a: Verifying Checksum
|
||||
18695ccc900a: Download complete
|
||||
ef8806083e82: Pull complete
|
||||
b74107c861c7: Pull complete
|
||||
adc935def003: Pull complete
|
||||
4f4fb700ef54: Pull complete
|
||||
18695ccc900a: Pull complete
|
||||
45d119d5c397: Pull complete
|
||||
dac52db4fc51: Pull complete
|
||||
6d598f86b2f2: Pull complete
|
||||
8aa349c8396c: Pull complete
|
||||
Digest: sha256:eb3733681db8757412632c61a99ad656f0d94ed6781bb2ea114b4d70babab78c
|
||||
Status: Downloaded newer image for gtstef/filebrowser:1.3.3-stable
|
||||
docker.io/gtstef/filebrowser:1.3.3-stable
|
||||
1.1.0: Pulling from admin/felhom-samba
|
||||
897d797d2723: Pulling fs layer
|
||||
3051591aa250: Pulling fs layer
|
||||
ce57a3f93416: Pulling fs layer
|
||||
fb94eeec2fe1: Pulling fs layer
|
||||
fb94eeec2fe1: Waiting
|
||||
ce57a3f93416: Verifying Checksum
|
||||
ce57a3f93416: Download complete
|
||||
fb94eeec2fe1: Verifying Checksum
|
||||
fb94eeec2fe1: Download complete
|
||||
897d797d2723: Verifying Checksum
|
||||
897d797d2723: Download complete
|
||||
3051591aa250: Verifying Checksum
|
||||
3051591aa250: Download complete
|
||||
897d797d2723: Pull complete
|
||||
3051591aa250: Pull complete
|
||||
ce57a3f93416: Pull complete
|
||||
fb94eeec2fe1: Pull complete
|
||||
Digest: sha256:1c17c09422bec0366d7cf0e0fcfc1486ba6c90334a0a5d5c851073a9342f8f10
|
||||
Status: Downloaded newer image for gitea.dooplex.hu/admin/felhom-samba:1.1.0
|
||||
gitea.dooplex.hu/admin/felhom-samba:1.1.0
|
||||
[golden] baking the controller-bootstrap unit (deploys the BAKED controller from the config mount) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-controller-bootstrap.service' → '/etc/systemd/system/felhom-controller-bootstrap.service'.
|
||||
[golden] baking the controller-bootstrap PATH unit (starts the service on bootstrap-mount hot-plug — B1) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-controller-bootstrap.path' → '/etc/systemd/system/felhom-controller-bootstrap.path'.
|
||||
[golden] baking the first-boot SSH host-key regeneration unit (F3) …
|
||||
Created symlink '/etc/systemd/system/multi-user.target.wants/felhom-regen-hostkeys.service' → '/etc/systemd/system/felhom-regen-hostkeys.service'.
|
||||
[golden] identity-clean + minimize …
|
||||
[golden] stop + archive …
|
||||
INFO: including mount point rootfs ('/') in backup
|
||||
INFO: including mount point mp0 ('/var/lib/felhom') in backup
|
||||
INFO: archive file size: 627MB
|
||||
INFO: Finished Backup of VM 9100 (00:00:41)
|
||||
[golden] DONE. golden archive volid: local:backup/vzdump-lxc-9100-2026_08_31-16_15_14.tar.zst (rootfs 32G + ONE data volume 24G @ /var/lib/felhom, all in the archive)
|
||||
[golden] publishing golden (657873700 bytes, sha256 9287f7cef5f13166…) → https://gitea.dooplex.hu/api/packages/admin/generic/felhom-golden/0.230.0/golden.tar.zst
|
||||
[golden] pre-delete existing: HTTP 404 (404/204 expected)
|
||||
[golden] upload OK (HTTP 201)
|
||||
GOLDEN_VERSION=0.230.0
|
||||
GOLDEN_SHA256=9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
[golden] Record in the hub operator UI (Configs → Day-0 artifacts): golden 0.230.0 / 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
[golden] (the build guest 9100 is stopped; destroy it with: pct destroy 9100 --purge)
|
||||
@@ -0,0 +1,13 @@
|
||||
+ pct destroy 9100 --purge
|
||||
Logical volume "vm-9100-disk-0" successfully removed.
|
||||
Logical volume "vm-9100-disk-1" successfully removed.
|
||||
purging CT 9100 from related configurations..
|
||||
+ shred -u /root/.gitea-token /root/bake-run.sh /root/build-golden.sh /root/bake.log
|
||||
+ ls -A /root
|
||||
+ grep -iE 'gitea-token|bake|build-golden'
|
||||
leftovers-rc=1 (1 = clean)
|
||||
+ echo 'leftovers-rc=1 (1 = clean)'
|
||||
+ pct list
|
||||
Snapshot list:
|
||||
ID TAG VM_SIZE DATE VM_CLOCK ICOUNT
|
||||
1 virgin 0 B 2026-07-03 14:12:15 0000:00:00.000 0
|
||||
@@ -0,0 +1,4 @@
|
||||
=== ROUND TRIP: download the published bytes and hash THEM, not the local file ===
|
||||
http=200 bytes=657873700
|
||||
downloaded sha256: 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
bake printed : 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
@@ -0,0 +1,9 @@
|
||||
=== VOUCH: the THREE fields moved together (R-216 shape avoided) ===
|
||||
golden_version 0.229.0 -> 0.230.0
|
||||
agent_version 0.130.0 -> 0.130.0 (UNCHANGED, already >= MinAgent)
|
||||
min_agent 0.129.0 -> 0.129.0 (UNCHANGED, v0.230.0 CHANGELOG says MinAgent: 0.129.0)
|
||||
min_agent (0.129.0) <= agent_version (0.130.0): the R-216 hold is satisfied
|
||||
|
||||
POST http=303
|
||||
--- location header (read from -D, never from %{redirect_url} — R-132) ---
|
||||
Location: /configuration?flash=artifacts_set
|
||||
@@ -0,0 +1,284 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration — Felhom Hub</title>
|
||||
<link rel="stylesheet" href="/style.css?v=0.109.0">
|
||||
</head>
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
|
||||
<symbol id="i-triangle-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /> <path d="M12 9v4" /> <path d="M12 17h.01" /></symbol>
|
||||
<symbol id="i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></symbol>
|
||||
<symbol id="i-server" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2" /> <rect width="20" height="8" x="2" y="14" rx="2" ry="2" /> <line x1="6" x2="6.01" y1="6" y2="6" /> <line x1="6" x2="6.01" y1="18" y2="18" /></symbol>
|
||||
<symbol id="i-settings" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /> <circle cx="12" cy="12" r="3" /></symbol>
|
||||
<symbol id="i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18" /> <path d="m6 6 12 12" /></symbol>
|
||||
<symbol id="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 16v-4" /> <path d="M12 8h.01" /></symbol>
|
||||
<symbol id="i-hard-drive" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 16h.01" /> <path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" /> <path d="M21.946 12.013H2.054" /> <path d="M6 16h.01" /></symbol>
|
||||
<symbol id="i-cpu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20v2" /> <path d="M12 2v2" /> <path d="M17 20v2" /> <path d="M17 2v2" /> <path d="M2 12h2" /> <path d="M2 17h2" /> <path d="M2 7h2" /> <path d="M20 12h2" /> <path d="M20 17h2" /> <path d="M20 7h2" /> <path d="M7 20v2" /> <path d="M7 2v2" /> <rect x="4" y="4" width="16" height="16" rx="2" /> <rect x="8" y="8" width="8" height="8" rx="1" /></symbol>
|
||||
<symbol id="i-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 6v6l4 2" /></symbol>
|
||||
<symbol id="i-boxes" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /> <path d="m7 16.5-4.74-2.85" /> <path d="m7 16.5 5-3" /> <path d="M7 16.5v5.17" /> <path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /> <path d="m17 16.5-5-3" /> <path d="m17 16.5 4.74-2.85" /> <path d="M17 16.5v5.17" /> <path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" /> <path d="M12 8 7.26 5.15" /> <path d="m12 8 4.74-2.85" /> <path d="M12 13.5V8" /></symbol>
|
||||
<symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /> <path d="M16 3.128a4 4 0 0 1 0 7.744" /> <path d="M22 21v-2a4 4 0 0 0-3-3.87" /> <circle cx="9" cy="7" r="4" /></symbol>
|
||||
</svg>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Felhom <span>Hub</span></h1>
|
||||
<nav class="nav-links">
|
||||
<a href="/" class="nav-link">Dashboard</a>
|
||||
<a href="/configs" class="nav-link">Customers</a>
|
||||
<a href="/apps" class="nav-link">Apps</a>
|
||||
<a href="/hosts" class="nav-link">Hosts</a>
|
||||
<a href="/offsite" class="nav-link">Offsite</a>
|
||||
<a href="/configuration" class="nav-link active">Configuration</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<h2 style="margin-bottom: 1rem;">Configuration</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Managed updates — global floor</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The minimum controller version every box auto-updates to (unless a per-customer override is set).
|
||||
<strong>Saving takes effect immediately</strong> — boxes below the floor update on their next
|
||||
report, no customer action. Blank = no global floor. This setting is independent of the Day-0
|
||||
artifact manifest below.
|
||||
</p>
|
||||
|
||||
<p style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
Effective floor:
|
||||
<code>v0.229.0</code>
|
||||
|
||||
<span style="color: #cbd5e1;">— source: <strong>DB (hub_settings)</strong>; env fallback would be <code>v0.120.0</code></span>
|
||||
|
||||
</p>
|
||||
<form id="global-floor-form" method="POST" action="/configuration/global-floor" style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="text" id="global-floor-input" name="min_controller_version" value="0.229.0" placeholder="e.g. 0.86.0 (blank = clear DB override)" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="confirmGlobalFloor()">Save global floor…</button>
|
||||
<span style="font-size: 0.85em; color: #cbd5e1;">DB override: <code>v0.229.0</code></span>
|
||||
</form>
|
||||
<div id="global-floor-confirm" style="display: none; margin-top: 0.75rem; padding: 0.75rem; border: 1px solid #7c3f00; background: #241a0a; border-radius: 6px; max-width: 44em;">
|
||||
<p id="global-floor-impact" style="margin: 0 0 0.5rem; font-size: 0.9em;">…</p>
|
||||
<p style="margin: 0 0 0.5rem; font-size: 0.85em; color: #cbd5e1;">Type the version again to confirm (or <code>CLEAR</code> to remove the DB override):</p>
|
||||
<input type="text" id="global-floor-confirm-input" placeholder="retype the version…" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="submitGlobalFloor()">Confirm & apply</button>
|
||||
<button class="btn btn-sm btn-ghost" type="button" onclick="document.getElementById('global-floor-confirm').style.display='none';">Cancel</button>
|
||||
<p id="global-floor-confirm-err" style="margin: 0.4em 0 0; font-size: 0.8em; color: #f87171;"></p>
|
||||
</div>
|
||||
<script>
|
||||
function confirmGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var box = document.getElementById('global-floor-confirm');
|
||||
var impact = document.getElementById('global-floor-impact');
|
||||
document.getElementById('global-floor-confirm-input').value = '';
|
||||
document.getElementById('global-floor-confirm-err').textContent = '';
|
||||
box.style.display = 'block';
|
||||
if (v === '') {
|
||||
impact.textContent = 'This will CLEAR the DB floor override (the box falls back to the env default). Type CLEAR to confirm.';
|
||||
return;
|
||||
}
|
||||
impact.textContent = 'Checking blast radius…';
|
||||
fetch('/configuration/global-floor/impact?v=' + encodeURIComponent(v))
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d){
|
||||
if (!d.valid) { impact.textContent = 'Invalid version — use X.Y.Z.'; return; }
|
||||
impact.textContent = 'Saving the minimum version v' + d.version +
|
||||
' takes effect immediately — currently ' + d.below +
|
||||
' box(es) are below this version and would update on their next report.';
|
||||
})
|
||||
.catch(function(){ impact.textContent = 'Could not compute the blast radius; proceed with caution.'; });
|
||||
}
|
||||
function submitGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var typed = document.getElementById('global-floor-confirm-input').value.trim();
|
||||
var err = document.getElementById('global-floor-confirm-err');
|
||||
var expected = (v === '') ? 'CLEAR' : v;
|
||||
if (typed !== expected) { err.textContent = 'Confirmation does not match (' + expected + ').'; return; }
|
||||
document.getElementById('global-floor-form').submit();
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Day-0 artifacts — agent & golden</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The current agent binary + golden archive the host-bootstrap script fetches from Gitea and
|
||||
verifies (sha256) before installing. The hub vouches for these checksums (a different trust
|
||||
root than Gitea). Pick a version — the sha256 is read from Gitea automatically (no manual
|
||||
copy). Choose <em>— none —</em> to clear an artifact.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/artifacts" style="display: grid; grid-template-columns: auto 12em 1fr; gap: 0.5rem; align-items: center; max-width: 56em;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Agent</label>
|
||||
|
||||
<select name="agent_version" id="agent_version" onchange="syncArtifactSha('agent')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.130.0" data-sha="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" selected>0.130.0</option>
|
||||
|
||||
<option value="0.129.0" data-sha="53a54f0620afbd6d4a1b86607e2a84dfbe7a290f44ed38a9485d6d971eecde8d" >0.129.0</option>
|
||||
|
||||
<option value="0.128.0" data-sha="c6eba73bf9b9ad6980cfef57bfb3db31581abc9d643de2ff50d4254576fc1a59" >0.128.0</option>
|
||||
|
||||
<option value="0.127.0" data-sha="f0d2c89311f03fd2b9ab6ae242e09a724ff8ea1fd2214759bae247c5db7dbf72" >0.127.0</option>
|
||||
|
||||
<option value="0.126.0" data-sha="7ecf8e9cdba237bc2d81003440095eace6418d00c3a485f3ca77742a25e4a93b" >0.126.0</option>
|
||||
|
||||
<option value="0.125.0" data-sha="f7d8339b53d92a6c45be7eaf189469a041b6b00b758a64511c0479beae7016b3" >0.125.0</option>
|
||||
|
||||
<option value="0.124.1" data-sha="5c279bda64cdec8cbd76f8a800bcd602063bb17175f406b225775e7dece3a21c" >0.124.1</option>
|
||||
|
||||
<option value="0.124.0" data-sha="5e4179383bc838a7ad360efcfab5e8f02a2939ed8bcc4bc68ffd85ba02a5c9a4" >0.124.0</option>
|
||||
|
||||
<option value="0.123.0" data-sha="74910135ac4feb1b7f0ad4dbd1541d965cbc0fe70d4f47b62ebf7e4bfb962453" >0.123.0</option>
|
||||
|
||||
<option value="0.122.0" data-sha="d5f294e56c1ef59055e8e87fb9135aa477632dbbc56a5d4bff46bbd0466c1edf" >0.122.0</option>
|
||||
|
||||
<option value="0.121.1" data-sha="afaeeb509d1ed70d6e6bebac0393a3cd5be59d51e3db9ff96ef8524bd78546d7" >0.121.1</option>
|
||||
|
||||
<option value="0.121.0" data-sha="b2128f3cd4539225a2842f541f56ffaf5390b1d97f3f3a80076ec5f53dbc7d7a" >0.121.0</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="agent_sha256" id="agent_sha256" value="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Golden</label>
|
||||
|
||||
<select name="golden_version" id="golden_version" onchange="syncArtifactSha('golden')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.230.0" data-sha="9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e" selected>0.230.0</option>
|
||||
|
||||
<option value="0.229.0" data-sha="39aa886df77b21757aef3b298a389343dc0df5134bb0f14e8f92a451d7bdae87" >0.229.0</option>
|
||||
|
||||
<option value="0.228.0" data-sha="76a3a98b9e7cc23bf8ae51b38a6272f576df285cb34cd22235ac3f06a31e53ec" >0.228.0</option>
|
||||
|
||||
<option value="0.227.1" data-sha="66754491dc9bd0130ef8ded9562f63c53a5ffdcfd91baa551141e55fa083ea32" >0.227.1</option>
|
||||
|
||||
<option value="0.226.1" data-sha="70ed8e9377dec22a9b493e55f222b0e25a49d7f3caec8c506e0412fd6baefe69" >0.226.1</option>
|
||||
|
||||
<option value="0.223.0" data-sha="9eaf39ac39219b42ec9e6cbf890275febcdcc6f53325fe0c0f591d3431044f17" >0.223.0</option>
|
||||
|
||||
<option value="0.222.0" data-sha="19f5904f53792684f046ec0bc25426645cb87ad73d5cfc6c03639d9f82706037" >0.222.0</option>
|
||||
|
||||
<option value="0.221.1" data-sha="1c8bf6cf08cadabeca6331f38360d905e867c235067cd10c2716915b6e6df089" >0.221.1</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="golden_sha256" id="golden_sha256" value="9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Min agent</label>
|
||||
<input type="text" name="min_agent" value="0.129.0" placeholder="e.g. 0.81.0 (blank = uncoupled)" style="padding: 0.3em 0.5em;">
|
||||
<span style="font-size: 0.8em; color: #94a6bf;">The golden's controller CHANGELOG <code>MinAgent:</code>. The hub HOLDS the floor for any box whose agent is below this — blank = uncoupled release, no gating.</span>
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">PBS wrapper</label>
|
||||
<input type="text" name="wrapper_sha256" value="104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3" placeholder="64-hex sha256 (blank = not vouched)" style="grid-column: 2 / 4; padding: 0.3em 0.5em; font-family: monospace;">
|
||||
<span></span>
|
||||
<span style="grid-column: 2 / 4; font-size: 0.8em; color: #94a6bf;">sha256 of <code>configs/felhom-pbs-apply</code> (R-50b). Unlike the agent and golden this root-owned wrapper is installed from <code>raw/branch/main</code> — unversioned and unpinned. Recording it here does not fix the channel; it makes host drift <em>visible</em>: agents report the installed file's hash and a mismatch is surfaced on the host page.</span>
|
||||
<span></span><span></span>
|
||||
<button class="btn btn-sm" type="submit" style="justify-self: start;">Save artifact manifest</button>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function syncArtifactSha(kind) {
|
||||
var sel = document.getElementById(kind + '_version');
|
||||
var sha = document.getElementById(kind + '_sha256');
|
||||
if (!sel || !sha) return;
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
sha.value = (opt && opt.getAttribute('data-sha')) || '';
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Login password</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The password for signing in to this hub UI. <strong>Changing it takes effect immediately</strong>
|
||||
for the next sign-in — your current session stays logged in. Enter your current password to confirm.
|
||||
If you ever lose it, the deployment ConfigMap (<code>auth.password_hash</code>) remains the reset path.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/password" style="display: grid; grid-template-columns: auto 20em; gap: 0.5rem; align-items: center; max-width: 40em;"
|
||||
onsubmit="return felhomCheckNewPw(this);">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Current password</label>
|
||||
<input type="password" name="current_password" autocomplete="current-password" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">New password</label>
|
||||
<input type="password" id="new_password" name="new_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Confirm new password</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="btn btn-sm" type="submit">Change password</button>
|
||||
<span id="pw-client-err" style="margin-left: 0.6em; font-size: 0.8em; color: #f87171;"></span>
|
||||
</span>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function felhomCheckNewPw(form) {
|
||||
var a = form.new_password.value;
|
||||
var b = form.confirm_password.value;
|
||||
var err = document.getElementById('pw-client-err');
|
||||
err.textContent = '';
|
||||
if (a.length < 8) { err.textContent = 'New password must be at least 8 characters.'; return false; }
|
||||
if (a !== b) { err.textContent = 'New password and confirmation do not match.'; return false; }
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Assets</h3>
|
||||
<p class="text-muted" style="margin-bottom: 1rem;">
|
||||
App logos and screenshots served to controllers. Assets are seeded from the Docker image
|
||||
and synced to controllers daily via the asset manifest API.
|
||||
</p>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="label">Files in manifest</span>
|
||||
<span class="value">211</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">Manifest generated</span>
|
||||
<span class="value" style="font-family: var(--font-mono); font-size: 0.85em;">2026-08-30T16:51:40Z</span>
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/configuration" style="margin-top: 1rem;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="hidden" name="action" value="refresh_assets">
|
||||
<button type="submit" class="btn" onclick="this.disabled=true;this.textContent='Refreshing…';this.form.submit();">Refresh Assets from Image</button>
|
||||
</form>
|
||||
<p class="text-muted" style="margin-top: 0.75rem; font-size: 0.8rem;">
|
||||
Re-reads the baked-in asset seed directory and updates changed files.
|
||||
Controllers will pick up changes on their next daily sync or manual trigger.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<footer style="margin-top: 2rem; color: var(--text-muted); font-size: 0.8rem; text-align: center;">
|
||||
Felhom Hub <span style="font-family: var(--font-mono)">0.109.0</span>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
=== PERSISTED STATE, re-read from the page (a 303 + success flash is not proof) ===
|
||||
agent_version SELECTED = 0.130.0 sha=a56a92a7bd68f5b46736eaec...
|
||||
golden_version SELECTED = 0.230.0 sha=9287f7cef5f13166276e8406...
|
||||
min_agent value = 0.129.0
|
||||
golden_sha256 value = 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
agent_sha256 value = a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3
|
||||
wrapper_sha256 value = 104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3
|
||||
|
||||
refusal banner present? False
|
||||
@@ -0,0 +1,3 @@
|
||||
newest released controller : 0.230.0 (## v0.230.0 — a poorer copy must never delete a richer one (2026-08-31, R-403))
|
||||
newest golden baked : 0.230.0 (documentation/tests/golden-0.230.0-2026-08-31)
|
||||
golden currency gate OK — the newest released controller has a golden (NOTE: this checks the BAKE, not the vouch — see the module docstring)
|
||||
@@ -0,0 +1,284 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration — Felhom Hub</title>
|
||||
<link rel="stylesheet" href="/style.css?v=0.109.0">
|
||||
</head>
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
|
||||
<symbol id="i-triangle-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /> <path d="M12 9v4" /> <path d="M12 17h.01" /></symbol>
|
||||
<symbol id="i-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></symbol>
|
||||
<symbol id="i-server" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2" /> <rect width="20" height="8" x="2" y="14" rx="2" ry="2" /> <line x1="6" x2="6.01" y1="6" y2="6" /> <line x1="6" x2="6.01" y1="18" y2="18" /></symbol>
|
||||
<symbol id="i-settings" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /> <circle cx="12" cy="12" r="3" /></symbol>
|
||||
<symbol id="i-x" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18" /> <path d="m6 6 12 12" /></symbol>
|
||||
<symbol id="i-info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 16v-4" /> <path d="M12 8h.01" /></symbol>
|
||||
<symbol id="i-hard-drive" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 16h.01" /> <path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" /> <path d="M21.946 12.013H2.054" /> <path d="M6 16h.01" /></symbol>
|
||||
<symbol id="i-cpu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20v2" /> <path d="M12 2v2" /> <path d="M17 20v2" /> <path d="M17 2v2" /> <path d="M2 12h2" /> <path d="M2 17h2" /> <path d="M2 7h2" /> <path d="M20 12h2" /> <path d="M20 17h2" /> <path d="M20 7h2" /> <path d="M7 20v2" /> <path d="M7 2v2" /> <rect x="4" y="4" width="16" height="16" rx="2" /> <rect x="8" y="8" width="8" height="8" rx="1" /></symbol>
|
||||
<symbol id="i-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" /> <path d="M12 6v6l4 2" /></symbol>
|
||||
<symbol id="i-boxes" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /> <path d="m7 16.5-4.74-2.85" /> <path d="m7 16.5 5-3" /> <path d="M7 16.5v5.17" /> <path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /> <path d="m17 16.5-5-3" /> <path d="m17 16.5 4.74-2.85" /> <path d="M17 16.5v5.17" /> <path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" /> <path d="M12 8 7.26 5.15" /> <path d="m12 8 4.74-2.85" /> <path d="M12 13.5V8" /></symbol>
|
||||
<symbol id="i-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /> <path d="M16 3.128a4 4 0 0 1 0 7.744" /> <path d="M22 21v-2a4 4 0 0 0-3-3.87" /> <circle cx="9" cy="7" r="4" /></symbol>
|
||||
</svg>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Felhom <span>Hub</span></h1>
|
||||
<nav class="nav-links">
|
||||
<a href="/" class="nav-link">Dashboard</a>
|
||||
<a href="/configs" class="nav-link">Customers</a>
|
||||
<a href="/apps" class="nav-link">Apps</a>
|
||||
<a href="/hosts" class="nav-link">Hosts</a>
|
||||
<a href="/offsite" class="nav-link">Offsite</a>
|
||||
<a href="/configuration" class="nav-link active">Configuration</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<h2 style="margin-bottom: 1rem;">Configuration</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Managed updates — global floor</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The minimum controller version every box auto-updates to (unless a per-customer override is set).
|
||||
<strong>Saving takes effect immediately</strong> — boxes below the floor update on their next
|
||||
report, no customer action. Blank = no global floor. This setting is independent of the Day-0
|
||||
artifact manifest below.
|
||||
</p>
|
||||
|
||||
<p style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
Effective floor:
|
||||
<code>v0.230.0</code>
|
||||
|
||||
<span style="color: #cbd5e1;">— source: <strong>DB (hub_settings)</strong>; env fallback would be <code>v0.120.0</code></span>
|
||||
|
||||
</p>
|
||||
<form id="global-floor-form" method="POST" action="/configuration/global-floor" style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="text" id="global-floor-input" name="min_controller_version" value="0.230.0" placeholder="e.g. 0.86.0 (blank = clear DB override)" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="confirmGlobalFloor()">Save global floor…</button>
|
||||
<span style="font-size: 0.85em; color: #cbd5e1;">DB override: <code>v0.230.0</code></span>
|
||||
</form>
|
||||
<div id="global-floor-confirm" style="display: none; margin-top: 0.75rem; padding: 0.75rem; border: 1px solid #7c3f00; background: #241a0a; border-radius: 6px; max-width: 44em;">
|
||||
<p id="global-floor-impact" style="margin: 0 0 0.5rem; font-size: 0.9em;">…</p>
|
||||
<p style="margin: 0 0 0.5rem; font-size: 0.85em; color: #cbd5e1;">Type the version again to confirm (or <code>CLEAR</code> to remove the DB override):</p>
|
||||
<input type="text" id="global-floor-confirm-input" placeholder="retype the version…" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button class="btn btn-sm" type="button" onclick="submitGlobalFloor()">Confirm & apply</button>
|
||||
<button class="btn btn-sm btn-ghost" type="button" onclick="document.getElementById('global-floor-confirm').style.display='none';">Cancel</button>
|
||||
<p id="global-floor-confirm-err" style="margin: 0.4em 0 0; font-size: 0.8em; color: #f87171;"></p>
|
||||
</div>
|
||||
<script>
|
||||
function confirmGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var box = document.getElementById('global-floor-confirm');
|
||||
var impact = document.getElementById('global-floor-impact');
|
||||
document.getElementById('global-floor-confirm-input').value = '';
|
||||
document.getElementById('global-floor-confirm-err').textContent = '';
|
||||
box.style.display = 'block';
|
||||
if (v === '') {
|
||||
impact.textContent = 'This will CLEAR the DB floor override (the box falls back to the env default). Type CLEAR to confirm.';
|
||||
return;
|
||||
}
|
||||
impact.textContent = 'Checking blast radius…';
|
||||
fetch('/configuration/global-floor/impact?v=' + encodeURIComponent(v))
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d){
|
||||
if (!d.valid) { impact.textContent = 'Invalid version — use X.Y.Z.'; return; }
|
||||
impact.textContent = 'Saving the minimum version v' + d.version +
|
||||
' takes effect immediately — currently ' + d.below +
|
||||
' box(es) are below this version and would update on their next report.';
|
||||
})
|
||||
.catch(function(){ impact.textContent = 'Could not compute the blast radius; proceed with caution.'; });
|
||||
}
|
||||
function submitGlobalFloor() {
|
||||
var v = document.getElementById('global-floor-input').value.trim();
|
||||
var typed = document.getElementById('global-floor-confirm-input').value.trim();
|
||||
var err = document.getElementById('global-floor-confirm-err');
|
||||
var expected = (v === '') ? 'CLEAR' : v;
|
||||
if (typed !== expected) { err.textContent = 'Confirmation does not match (' + expected + ').'; return; }
|
||||
document.getElementById('global-floor-form').submit();
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Day-0 artifacts — agent & golden</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The current agent binary + golden archive the host-bootstrap script fetches from Gitea and
|
||||
verifies (sha256) before installing. The hub vouches for these checksums (a different trust
|
||||
root than Gitea). Pick a version — the sha256 is read from Gitea automatically (no manual
|
||||
copy). Choose <em>— none —</em> to clear an artifact.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/artifacts" style="display: grid; grid-template-columns: auto 12em 1fr; gap: 0.5rem; align-items: center; max-width: 56em;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Agent</label>
|
||||
|
||||
<select name="agent_version" id="agent_version" onchange="syncArtifactSha('agent')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.130.0" data-sha="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" selected>0.130.0</option>
|
||||
|
||||
<option value="0.129.0" data-sha="53a54f0620afbd6d4a1b86607e2a84dfbe7a290f44ed38a9485d6d971eecde8d" >0.129.0</option>
|
||||
|
||||
<option value="0.128.0" data-sha="c6eba73bf9b9ad6980cfef57bfb3db31581abc9d643de2ff50d4254576fc1a59" >0.128.0</option>
|
||||
|
||||
<option value="0.127.0" data-sha="f0d2c89311f03fd2b9ab6ae242e09a724ff8ea1fd2214759bae247c5db7dbf72" >0.127.0</option>
|
||||
|
||||
<option value="0.126.0" data-sha="7ecf8e9cdba237bc2d81003440095eace6418d00c3a485f3ca77742a25e4a93b" >0.126.0</option>
|
||||
|
||||
<option value="0.125.0" data-sha="f7d8339b53d92a6c45be7eaf189469a041b6b00b758a64511c0479beae7016b3" >0.125.0</option>
|
||||
|
||||
<option value="0.124.1" data-sha="5c279bda64cdec8cbd76f8a800bcd602063bb17175f406b225775e7dece3a21c" >0.124.1</option>
|
||||
|
||||
<option value="0.124.0" data-sha="5e4179383bc838a7ad360efcfab5e8f02a2939ed8bcc4bc68ffd85ba02a5c9a4" >0.124.0</option>
|
||||
|
||||
<option value="0.123.0" data-sha="74910135ac4feb1b7f0ad4dbd1541d965cbc0fe70d4f47b62ebf7e4bfb962453" >0.123.0</option>
|
||||
|
||||
<option value="0.122.0" data-sha="d5f294e56c1ef59055e8e87fb9135aa477632dbbc56a5d4bff46bbd0466c1edf" >0.122.0</option>
|
||||
|
||||
<option value="0.121.1" data-sha="afaeeb509d1ed70d6e6bebac0393a3cd5be59d51e3db9ff96ef8524bd78546d7" >0.121.1</option>
|
||||
|
||||
<option value="0.121.0" data-sha="b2128f3cd4539225a2842f541f56ffaf5390b1d97f3f3a80076ec5f53dbc7d7a" >0.121.0</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="agent_sha256" id="agent_sha256" value="a56a92a7bd68f5b46736eaec4806c3d26c16ccb35118c4ac0e3d8094eaefabc3" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Golden</label>
|
||||
|
||||
<select name="golden_version" id="golden_version" onchange="syncArtifactSha('golden')" style="padding: 0.3em 0.5em;">
|
||||
<option value="" data-sha="">— none —</option>
|
||||
|
||||
<option value="0.230.0" data-sha="9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e" selected>0.230.0</option>
|
||||
|
||||
<option value="0.229.0" data-sha="39aa886df77b21757aef3b298a389343dc0df5134bb0f14e8f92a451d7bdae87" >0.229.0</option>
|
||||
|
||||
<option value="0.228.0" data-sha="76a3a98b9e7cc23bf8ae51b38a6272f576df285cb34cd22235ac3f06a31e53ec" >0.228.0</option>
|
||||
|
||||
<option value="0.227.1" data-sha="66754491dc9bd0130ef8ded9562f63c53a5ffdcfd91baa551141e55fa083ea32" >0.227.1</option>
|
||||
|
||||
<option value="0.226.1" data-sha="70ed8e9377dec22a9b493e55f222b0e25a49d7f3caec8c506e0412fd6baefe69" >0.226.1</option>
|
||||
|
||||
<option value="0.223.0" data-sha="9eaf39ac39219b42ec9e6cbf890275febcdcc6f53325fe0c0f591d3431044f17" >0.223.0</option>
|
||||
|
||||
<option value="0.222.0" data-sha="19f5904f53792684f046ec0bc25426645cb87ad73d5cfc6c03639d9f82706037" >0.222.0</option>
|
||||
|
||||
<option value="0.221.1" data-sha="1c8bf6cf08cadabeca6331f38360d905e867c235067cd10c2716915b6e6df089" >0.221.1</option>
|
||||
|
||||
</select>
|
||||
|
||||
<input type="text" name="golden_sha256" id="golden_sha256" value="9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e" readonly placeholder="64-hex sha256 (blank = none)" style="padding: 0.3em 0.5em; font-family: monospace; opacity: 0.7;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Min agent</label>
|
||||
<input type="text" name="min_agent" value="0.129.0" placeholder="e.g. 0.81.0 (blank = uncoupled)" style="padding: 0.3em 0.5em;">
|
||||
<span style="font-size: 0.8em; color: #94a6bf;">The golden's controller CHANGELOG <code>MinAgent:</code>. The hub HOLDS the floor for any box whose agent is below this — blank = uncoupled release, no gating.</span>
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">PBS wrapper</label>
|
||||
<input type="text" name="wrapper_sha256" value="104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3" placeholder="64-hex sha256 (blank = not vouched)" style="grid-column: 2 / 4; padding: 0.3em 0.5em; font-family: monospace;">
|
||||
<span></span>
|
||||
<span style="grid-column: 2 / 4; font-size: 0.8em; color: #94a6bf;">sha256 of <code>configs/felhom-pbs-apply</code> (R-50b). Unlike the agent and golden this root-owned wrapper is installed from <code>raw/branch/main</code> — unversioned and unpinned. Recording it here does not fix the channel; it makes host drift <em>visible</em>: agents report the installed file's hash and a mismatch is surfaced on the host page.</span>
|
||||
<span></span><span></span>
|
||||
<button class="btn btn-sm" type="submit" style="justify-self: start;">Save artifact manifest</button>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function syncArtifactSha(kind) {
|
||||
var sel = document.getElementById(kind + '_version');
|
||||
var sha = document.getElementById(kind + '_sha256');
|
||||
if (!sel || !sha) return;
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
sha.value = (opt && opt.getAttribute('data-sha')) || '';
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Login password</h3>
|
||||
<p class="text-muted" style="margin: 0 0 0.75rem; font-size: 0.85em;">
|
||||
The password for signing in to this hub UI. <strong>Changing it takes effect immediately</strong>
|
||||
for the next sign-in — your current session stays logged in. Enter your current password to confirm.
|
||||
If you ever lose it, the deployment ConfigMap (<code>auth.password_hash</code>) remains the reset path.
|
||||
</p>
|
||||
<form method="POST" action="/configuration/password" style="display: grid; grid-template-columns: auto 20em; gap: 0.5rem; align-items: center; max-width: 40em;"
|
||||
onsubmit="return felhomCheckNewPw(this);">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Current password</label>
|
||||
<input type="password" name="current_password" autocomplete="current-password" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">New password</label>
|
||||
<input type="password" id="new_password" name="new_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<label style="font-size: 0.9em; color: #cbd5e1;">Confirm new password</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" autocomplete="new-password" minlength="8" maxlength="72" required style="padding: 0.3em 0.5em;">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="btn btn-sm" type="submit">Change password</button>
|
||||
<span id="pw-client-err" style="margin-left: 0.6em; font-size: 0.8em; color: #f87171;"></span>
|
||||
</span>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
||||
function felhomCheckNewPw(form) {
|
||||
var a = form.new_password.value;
|
||||
var b = form.confirm_password.value;
|
||||
var err = document.getElementById('pw-client-err');
|
||||
err.textContent = '';
|
||||
if (a.length < 8) { err.textContent = 'New password must be at least 8 characters.'; return false; }
|
||||
if (a !== b) { err.textContent = 'New password and confirmation do not match.'; return false; }
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="card">
|
||||
<h3 style="margin-top: 0;">Assets</h3>
|
||||
<p class="text-muted" style="margin-bottom: 1rem;">
|
||||
App logos and screenshots served to controllers. Assets are seeded from the Docker image
|
||||
and synced to controllers daily via the asset manifest API.
|
||||
</p>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="label">Files in manifest</span>
|
||||
<span class="value">211</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">Manifest generated</span>
|
||||
<span class="value" style="font-family: var(--font-mono); font-size: 0.85em;">2026-08-30T16:51:40Z</span>
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/configuration" style="margin-top: 1rem;">
|
||||
<input type="hidden" name="_csrf" value="">
|
||||
<input type="hidden" name="action" value="refresh_assets">
|
||||
<button type="submit" class="btn" onclick="this.disabled=true;this.textContent='Refreshing…';this.form.submit();">Refresh Assets from Image</button>
|
||||
</form>
|
||||
<p class="text-muted" style="margin-top: 0.75rem; font-size: 0.8rem;">
|
||||
Re-reads the baked-in asset seed directory and updates changed files.
|
||||
Controllers will pick up changes on their next daily sync or manual trigger.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<footer style="margin-top: 2rem; color: var(--text-muted); font-size: 0.8rem; text-align: center;">
|
||||
Felhom Hub <span style="font-family: var(--font-mono)">0.109.0</span>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
=== BEFORE: min_controller_version ===
|
||||
name="min_controller_version" value="0.229.0"
|
||||
|
||||
=== POST /configuration/global-floor 0.229.0 -> 0.230.0 ===
|
||||
POST http=303
|
||||
Location: /configuration?flash=floor_set
|
||||
|
||||
=== AFTER: re-read from the page, not from the flash ===
|
||||
name="min_controller_version" value="0.230.0"
|
||||
@@ -0,0 +1,30 @@
|
||||
=== watching demo-felhom for the POSITIVE observable (the image tag changing), not for an absent error ===
|
||||
t0=14:21:37Z starting tag=gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
[1] 14:21:39Z gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
SELF-UPDATE OBSERVED
|
||||
--- running container ---
|
||||
gitea.dooplex.hu/admin/felhom-controller:0.230.0 Up 8 seconds (healthy)
|
||||
=== HONEST NOTE: my first poll already read 0.230.0 — the update landed between the floor POST and 14:21:37Z.
|
||||
=== So the proof is the RESTART, not my polling. Container was 'Up 8 seconds' at first read.
|
||||
|
||||
--- controller startup line, demo-felhom ---
|
||||
perl: warning: Setting locale failed.
|
||||
perl: warning: Please check that your locale settings:
|
||||
LANGUAGE = (unset),
|
||||
LC_ALL = (unset),
|
||||
LC_CTYPE = "UTF-8",
|
||||
LC_NUMERIC = (unset),
|
||||
|
||||
--- the floor decision in the agent journal ---
|
||||
Aug 31 16:21:29 demo-felhom sudo[2071156]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- docker image inspect gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
Aug 31 16:21:29 demo-felhom sudo[2071169]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- tee /etc/felhom-controller-image
|
||||
Aug 31 16:21:30 demo-felhom felhom-agent[2564828]: time=2026-08-31T16:21:30.589+02:00 level=INFO msg="controller-swap: image file written, restarting bootstrap" vmid=9201 target=gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
Aug 31 16:21:30 demo-felhom sudo[2071175]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- systemctl restart felhom-controller-bootstrap.service
|
||||
Aug 31 16:21:31 demo-felhom sudo[2071294]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- docker inspect -f '{{.State.Running}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}|{{.Config.Image}}|{{.RestartCount}}' felhom-controller
|
||||
Aug 31 16:21:35 demo-felhom sudo[2071659]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- docker inspect -f '{{.State.Running}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}|{{.Config.Image}}|{{.RestartCount}}' felhom-controller
|
||||
Aug 31 16:21:39 demo-felhom sudo[2071976]: felhom-agent : PWD=/ ; USER=root ; COMMAND=/usr/sbin/pct exec 9201 -- docker inspect -f '{{.State.Running}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}|{{.Config.Image}}|{{.RestartCount}}' felhom-controller
|
||||
Aug 31 16:21:40 demo-felhom felhom-agent[2564828]: time=2026-08-31T16:21:40.156+02:00 level=INFO msg="controller-swap: new controller healthy" vmid=9201 target=gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
|
||||
--- both boxes now ---
|
||||
demo-felhom: gitea.dooplex.hu/admin/felhom-controller:0.230.0 Up 23 seconds (healthy)
|
||||
demo-hp : gitea.dooplex.hu/admin/felhom-controller:0.230.0 Up 2 hours (healthy)
|
||||
@@ -0,0 +1,9 @@
|
||||
=== re-download the PUBLISHED bytes and read INSIDE them ===
|
||||
http=200 bytes=657873700
|
||||
sha256 of the DOWNLOADED bytes: 9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e
|
||||
|
||||
--- the controller tag the DELIVERED artifact will start ---
|
||||
gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
|
||||
--- and the baked controller image is present in the archive's docker store ---
|
||||
19382
|
||||
@@ -0,0 +1,140 @@
|
||||
# Golden bake 0.230.0 — 2026-08-31
|
||||
|
||||
Baked, published, round-trip verified, **vouched**, and the fleet floor raised. `demo-felhom` picked
|
||||
up the new controller **by itself, unattended** — the agent's own journal is the proof, not an absent
|
||||
error.
|
||||
|
||||
**Why it was owed:** v0.230.0 is the build that stops a poorer copy deleting a richer one (R-403).
|
||||
Until this bake the newest golden was **0.229.0 — the build that has the defect** — so every fresh
|
||||
install and the whole fleet floor still carried it. `golden_currency_gate.py` had been RED since the
|
||||
v0.230.0 release and was red at `dddcc80`, `6e550ae`, `130f7a6` and `32a4c35`.
|
||||
|
||||
## What was produced
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `GOLDEN_VERSION` | **0.230.0** |
|
||||
| `GOLDEN_SHA256` | `9287f7cef5f13166276e8406005e3f28004004510c5184f1c1c7377f7aafad2e` |
|
||||
| size | **657 873 700 B** |
|
||||
| package URL | `…/api/packages/admin/generic/felhom-golden/0.230.0/golden.tar.zst` |
|
||||
| baked controller | `gitea.dooplex.hu/admin/felhom-controller:0.230.0` |
|
||||
| `MinAgent` | **0.129.0** — read from the controller `CHANGELOG.md` header, not assumed |
|
||||
| script | `build-golden.sh v3.0.0`, sha256 `7b0fb5cf…73b6a1` on DooPlex |
|
||||
| venue | the drill VM on DooPlex, reverted to `virgin` and **cold-booted** first (`pve-manager/9.2.2`) |
|
||||
| template | `debian-13-standard_13.6-1_amd64.tar.zst`, after `pveam update` — the virgin snapshot's INDEX is stale too, and that failure reads as a bogus `400 no such template` |
|
||||
| archive volid | `local:backup/vzdump-lxc-9100-2026_08_31-16_15_14.tar.zst` |
|
||||
| bake wall clock | ~16:11 → 16:15 CEST, `vzdump` leg 00:00:41 |
|
||||
|
||||
**One thing the 0.229.0 bake did that this one did not**, said plainly rather than left as an
|
||||
implied equivalence: the script's sha256 was **not** compared across the hop. It was `scp`'d
|
||||
file→file and its DooPlex-side sha is recorded above; a corrupted copy would have failed the bake
|
||||
rather than produced a wrong golden, but that is an argument, not a measurement.
|
||||
|
||||
## Acceptance markers — counted on the COMMITTED log, not eyeballed
|
||||
|
||||
```
|
||||
docker OK (overlay2 : 1
|
||||
including mount point rootfs : 1 (line 317)
|
||||
including mount point mp0 : 1 (line 318) <- there is no mp1 since v3.0.0 (R-165/R-233)
|
||||
upload OK (HTTP 201) : 1 (line 324)
|
||||
--- must be ZERO ---
|
||||
excluding : 0
|
||||
FATAL : 0
|
||||
```
|
||||
|
||||
**The zeroes are believable because the greps are shown to work on this file:** the same
|
||||
`including mount point` pattern that returns 0 for `excluding` returns 2 real lines. An instrument
|
||||
that can silently drop results is not a measurement.
|
||||
|
||||
## Three independent readers agreed before anything was vouched
|
||||
|
||||
1. **The bake itself** printed `GOLDEN_SHA256=9287f7ce…ad2e`.
|
||||
2. **The round trip** — the published bytes downloaded back: `HTTP 200`, `657 873 700 B`,
|
||||
sha256 `9287f7ce…ad2e`. The hash is of the **downloaded** bytes, never the local file.
|
||||
3. **The hub's Day-0 dropdown**, a different code path, read `data-sha="9287f7cef5f13166276e…"`
|
||||
straight from Gitea.
|
||||
|
||||
**And the delivered artifact names the controller it will start**, read out of the downloaded
|
||||
archive itself:
|
||||
|
||||
```
|
||||
$ tar --zstd -xOf golden.tar.zst ./etc/felhom-controller-image
|
||||
gitea.dooplex.hu/admin/felhom-controller:0.230.0
|
||||
```
|
||||
|
||||
with **19 382** entries under `var/lib/felhom/docker/` — the baked image store is in the archive, not
|
||||
a promise that it will be pulled later.
|
||||
|
||||
## Both pre-gates were proven able to see something first
|
||||
|
||||
| gate | negative result | the positive control that makes it believable |
|
||||
|---|---|---|
|
||||
| 404 pre-gate on the package URL | `HTTP 404` for 0.230.0 before the bake | the same URL shape returns `HTTP 200` for the controller image manifest, and the bake's own pre-delete logged `HTTP 404 (404/204 expected)` |
|
||||
| token-leak grep on the committed log | **0** in `06-bake.log` and `06-bake-clean.log` | the token appended to a throwaway copy of the same log greps **1**; the copy was then `shred -u`'d |
|
||||
|
||||
The token was also kept off every command line: the transient unit's own properties were grepped for
|
||||
it — `systemctl show golden-bake -p Environment -p ExecStart` → **0**, with the same seeded positive
|
||||
control returning **1**.
|
||||
|
||||
## The vouch — a THREE-field change, checked rather than assumed
|
||||
|
||||
| field | before | after | why |
|
||||
|---|---|---|---|
|
||||
| `golden_version` | 0.229.0 | **0.230.0** | the new bake |
|
||||
| `agent_version` | 0.130.0 | 0.130.0 | **unchanged** — already ≥ MinAgent |
|
||||
| `min_agent` | 0.129.0 | 0.129.0 | **unchanged** — v0.230.0's CHANGELOG header says `MinAgent: 0.129.0` |
|
||||
|
||||
`min_agent` (0.129.0) ≤ `agent_version` (0.130.0), so this is **not** the R-216 shape the hub holds
|
||||
against. Only one field actually moved, and that is stated rather than left to look like a one-field
|
||||
vouch performed carelessly.
|
||||
|
||||
`POST /configuration/artifacts` → `303 Location: /configuration?flash=artifacts_set`. **The flash was
|
||||
not treated as proof:** the page was re-read and the selected options confirmed
|
||||
(`golden_version` selected 0.230.0, sha `9287f7ce…`), and the R-120 refusal banner
|
||||
(`golden_behind_fleet`) confirmed **absent**.
|
||||
|
||||
## The fleet floor, and the unattended proof that it worked
|
||||
|
||||
`POST /configuration/global-floor` `min_controller_version` **0.229.0 → 0.230.0**, re-read from the
|
||||
page afterwards. This is a **separate setting from the Day-0 artifacts** — the page says so itself —
|
||||
and it is the one that moves the existing fleet rather than fresh installs.
|
||||
|
||||
**`demo-felhom` was on controller 0.229.0 — the R-403 build — and moved itself.** From the agent's
|
||||
journal on that host, which is a POSITIVE observable and not a missing error:
|
||||
|
||||
```
|
||||
16:21:30 controller-swap: image file written, restarting bootstrap target=…felhom-controller:0.230.0
|
||||
16:21:40 controller-swap: new controller healthy target=…felhom-controller:0.230.0
|
||||
```
|
||||
|
||||
**Honest note on the watch:** the polling loop's *first* read already said 0.230.0, so the transition
|
||||
was not observed by the loop. The evidence is the journal above plus the container reading
|
||||
`Up 8 seconds (healthy)` at that first read. Both boxes now:
|
||||
|
||||
```
|
||||
demo-felhom gitea.dooplex.hu/admin/felhom-controller:0.230.0 Up (healthy)
|
||||
demo-hp gitea.dooplex.hu/admin/felhom-controller:0.230.0 Up (healthy)
|
||||
```
|
||||
|
||||
## Teardown — all of it, and it is not "nothing was created"
|
||||
|
||||
`pct destroy 9100 --purge` (both logical volumes removed), then `shred -u` of the token, the runner
|
||||
script, `build-golden.sh` and `bake.log` **after** the log was copied out for evidence — `ls | grep`
|
||||
in `/root` returns nothing. Then `poweroff`, waited for the qemu process to actually exit (checked
|
||||
with `ps -eo comm`, **not** `pgrep -f`, which self-matches), and `qemu-img snapshot -a virgin`. The
|
||||
disk carries the single `virgin` snapshot and nothing else.
|
||||
|
||||
## Files here
|
||||
|
||||
| file | what |
|
||||
|---|---|
|
||||
| `01-preconditions.txt` | disk headroom, image present, MinAgent, hub state before |
|
||||
| `02-pveam.txt`, `03-template.txt` | the index refresh and the template download |
|
||||
| `04-staged.txt`, `05-bake-launch.txt` | staging + the token-leak check on the unit properties |
|
||||
| `06-bake.log`, `06-bake-clean.log` | the bake, raw and with the locale noise stripped |
|
||||
| `07-teardown-vm.txt` | destroy, shred, revert to virgin |
|
||||
| `08-roundtrip.txt`, `16-archive-content-proof.txt` | the published bytes, and what is inside them |
|
||||
| `00-`, `10-`, `13-hub-*.html` | the hub configuration page before, after the vouch, after the floor |
|
||||
| `09-vouch-post.txt`, `11-vouch-verified.txt`, `14-floor-raise.txt` | the two POSTs and their re-reads |
|
||||
| `12-golden-currency-gate.txt` | the gate that was red, now green |
|
||||
| `15-demo-felhom-selfupdate.txt` | the unattended pickup |
|
||||
Reference in New Issue
Block a user