feat(shares): R-7b Parts 1-2 — shares payload builder + tier-2 shares job (Model B')

Sibling shares source for the local cross-drive tier. Reuses the tier2Mirror seam,
selectTier2TargetFrom (narrow source-drive seam extracted from selectTier2Target),
tier2ReconcileRoots (pure extraction), tier2SafeRemove, the marker-LAST discipline
and the recordTier2* helpers. Per-app paths are untouched.

- shares_payload.go: deterministic _shares-manifest.json + best-effort passdb capture
- tier2_shares.go: per-source-drive legs -> cross-drive target, payload, marker LAST
- infra.SambaContainerName/SambaPassdbVolume/Mount: single source of truth for the
  container identity (renderer, stacks execs, backup execs, monitor all read it)
- RESERVED-NAME finding: ValidateSMBShareName did NOT exclude a leading underscore,
  so "_shares" was an accepted share name. Now refused; RunAllTier2 additionally
  skips a "_shares" stack loudly as defense in depth.
- fix: shareSourceDrive returned a slash-normalised path, which made the target
  selector's source-drive equality check miss (a group could target its own drive)
This commit is contained in:
2026-07-18 12:45:57 +02:00
parent 3dfc49e578
commit c81df55dcb
8 changed files with 1050 additions and 13 deletions
+3 -2
View File
@@ -22,8 +22,9 @@ import (
const (
// SambaStackName is the stack directory name under StacksDir (and the protected-stack key).
SambaStackName = "samba"
// sambaContainer is the fixed container name (set in the generated compose).
sambaContainer = "felhom-samba"
// sambaContainer is the fixed container name. Aliased from the RENDERER's constant so the compose
// this package writes and the execs it runs can never name different containers.
sambaContainer = infra.SambaContainerName
// sambaUID is the household uid/gid every SMB write is forced to, so apps (group 1000) and both
// backup tiers see consistent ownership.
sambaUID = 1000