docs(shares): R-7b v0.145.0 — CHANGELOG, CONTEXT, REUSE, README; caveats cleared
The samba_classify.go SCOPE NOTE and the README KNOWN GAP both described a gap that R-7b closes; both now describe the sibling-shares-source execution instead.
This commit is contained in:
@@ -1,5 +1,77 @@
|
||||
## Changelog
|
||||
|
||||
### v0.145.0 — R-7b: share data enters the live backup runs (Model B′) + samba liveness (2026-07-18)
|
||||
|
||||
**The „Felhőmentés" toggle on the Megosztás page is now true.** Before this release a customer could
|
||||
switch a share to „Felhőmentés: bekapcsolva" and the page would render exactly that while the files
|
||||
dropped on it were in **no backup at all** — `backup.RunTier2` short-circuits on `os.Stat(unitDir)`
|
||||
before the classification seam, and the offsite runner enumerates `GetOffboxApps()`. A share-only
|
||||
infra stack has neither a recovery unit nor an offbox toggle, so it fell through both engines. R-7b
|
||||
closes that with a **sibling shares source** in each tier.
|
||||
|
||||
**Model B′ (Viktor's ruling, 2026-07-18) and its invariant.** Share data enters the runs through
|
||||
NEW, ADDITIVE job/leg code that reuses the proven primitives — the tier-2 mirror seam, the restic
|
||||
wrappers, the soft-quota/enlargement gate, the status recorders — while leaving **every per-app engine
|
||||
path byte-identical**. Not Model A (a synthetic recovery unit breaks on multi-drive shares and wraps
|
||||
1 KB of JSON in dump machinery) and not engine-loop surgery. The invariant is enforced by test, in
|
||||
both tiers, with red-proofs.
|
||||
|
||||
- **Payload (`internal/backup/shares_payload.go`, new):** a staging dir holding
|
||||
`_shares-manifest.json` (the share definitions, sorted → **byte-deterministic** for an unchanged
|
||||
registry, so a no-op run gives the mirror nothing to rewrite) plus a **best-effort** `passdb.tar`
|
||||
captured from the samba container. A restore therefore returns the files, the share configuration
|
||||
AND the SMB password hash — not just bytes on a disk. The credential copy is SECRET-BEARING: 0600,
|
||||
never logged at INFO, never in a report or a committed file. A down container degrades to
|
||||
manifest-only and KEEPS any previously captured copy (a stale credential beats none for DR).
|
||||
- **Tier-2 shares job (`internal/backup/tier2_shares.go`, new):** runs after the per-stack loop in the
|
||||
same orchestrator run. Shares are grouped **by source drive** — a household's shares can span disks
|
||||
and each group needs its own cross-drive target — into
|
||||
`backups/secondary/_shares/<sourceDriveKey>/<share>` with the payload at `_payload/` and the layout
|
||||
marker written **LAST**. Reuses `selectTier2TargetFrom` (a narrow source-drive seam extracted from
|
||||
`selectTier2Target`; the headroom math is untouched), `tier2ReconcileRoots` (a pure extraction),
|
||||
`tier2SafeRemove` and the `recordTier2*` helpers.
|
||||
- **Offsite shares leg (`internal/backup/offbox_shares.go`, new):** ONE additional
|
||||
`restic backup --tag felhom-offbox --tag _shares` carrying the manifest staging dir plus every
|
||||
MANDATORY share folder, hooked in AFTER the per-app loop and BEFORE retention — so
|
||||
`forget --group-by host,tags` covers the `_shares` group with **no flag change**. Same enlargement
|
||||
arithmetic as the per-app gate. **Degradation contract:** a quota-blocked push falls back to the
|
||||
MANIFEST ONLY, never to nothing — definitions protection must not regress because the files stopped
|
||||
fitting.
|
||||
- **Restore „Megosztások" (`internal/backup/shares_restore.go`, new):** siblings of the per-app
|
||||
scratch/place pair. Files are merged **missing-only** (never overwriting) and every destination is
|
||||
**prefix-asserted** against registered LIVE storage roots — a snapshot is untrusted layout input, so
|
||||
a path that no longer sits under a live root is refused rather than created. Definitions merge with
|
||||
**existing-wins** (a restore must never silently flip a live share's settings; skipped ones are
|
||||
named in the flash). Then `ReconcileSamba` re-renders smb.conf, and the credential goes back into
|
||||
the named volume best-effort. Routes `POST /backup/shares/{restore,place}`.
|
||||
- **Samba liveness (the fold-in):** `monitor.EffectiveProtected` gains a settings-backed dynamic
|
||||
extra, so a dead sharing service raises the same protected-container issue → alert → Hungarian
|
||||
degradation e-mail as a dead traefik — but only while sharing is ON. It watches the **container**
|
||||
name (`infra.SambaContainerName`), which is deliberately NOT the stack name. **Finding: the
|
||||
alert/e-mail pipeline needed no further change** and no new event type is introduced, so the
|
||||
`allowedEventTypes` gotcha does not apply.
|
||||
- **UI truth-up:** the Megosztás page states per-tier status (2. mentés / távoli mentés, amber only on
|
||||
deviation) and links to the restore page. The reserved `_shares` key is mapped to „Megosztások" at
|
||||
the notification and Hungarian-prose boundaries ONLY — the persisted `EnlargedBlocked` set, the
|
||||
restic tag and the dest path keep the raw key, because templates index by it.
|
||||
- **RESERVED-NAME FINDING (the task's assumption was false):** `settings.nbNameRe` begins with
|
||||
`[A-Za-z0-9_]`, so „_shares" **was an accepted share name** — the underscore namespace was not in
|
||||
fact reserved. `ValidateSMBShareName` now refuses a leading underscore (on ADD only, so existing
|
||||
shares are never retroactively invalidated), and `RunAllTier2`/`RunOffboxBackup` additionally skip a
|
||||
`_shares` STACK loudly as defense in depth.
|
||||
- **`infra.SambaContainerName` / `SambaPassdbVolume` / `SambaPassdbMount`** become the single source of
|
||||
truth for the samba container identity — the compose renderer interpolates them, and stacks, backup
|
||||
and monitor all read them instead of repeating string literals.
|
||||
- **Bug found by test:** `shareSourceDrive` returned a slash-normalised path, which made the target
|
||||
selector's source-drive equality check miss — a share group could have targeted its own source
|
||||
drive (a same-disk copy pretending to be tier 2). Fixed; POSIX-only in effect, but real.
|
||||
- **Tests:** 24 new/extended cases in `internal/backup` + 2 in `internal/monitor`. **Six red-proofs
|
||||
run and reverted, all fired:** (1) shares leg appending into the app's argv → B′ isolation FAILS;
|
||||
(2) mandatory→offsite mapping inverted → Scenarios A+B FAIL; (3) manifest-only degradation dropped →
|
||||
Scenario C FAILS; (4) prefix-assert removed → place-guard traversal FAILS; (5) dynamic samba extra
|
||||
removed → Scenario E enabled-case FAILS; (6) shares destBase dropping the reserved segment → tier-2
|
||||
isolation FAILS.
|
||||
|
||||
### v0.144.0 — „Megosztás": LAN SMB file sharing (R-7 slice 1) (2026-07-18)
|
||||
|
||||
The customer turns on network sharing, sets ONE household SMB password, and exports folders. The box
|
||||
|
||||
Reference in New Issue
Block a user