Repository navigation
Labels
refactoringRefactoringRefactoring
Description
Context
Audit on 2026-11-09 found the same logic implemented several times, with drift between copies. No behaviour change is intended except where the copies already disagree (then the safer one wins and the release note says so).
Internal (internal/module, internal/tenant, internal/fleet):
- write-managed-file-if-changed in four forms (
fileEquals+ writes ~15x,exporterGuardFileCurrent, tenantwriteIfChanged, hand-written loops insecurity.go,system.go,monitoring_hub.go). systemdReloadlives ingpu.go:176(failure = warning); monitoring, hub and ssh call daemon-reload directly (failure = error).generatePasswordtwice with different alphabets (module/accounts.go:150,tenant/manager.go:421).- module-name list in four places (
defaultOrder,NewRegistry,config/distro.go:67,IsModuleEnabled); only the first two are tested. if homeBase == "" { homeBase = "/home" }14 times.shellQuote/shellQuoteCLIidentical;defaultRunLog/defaultFleetInventorynear-identical.- status output in
module.goRunAll,users.go(36 prints),lifecycle.go,quota.go,ssh.gobypassesinternal/uiand writes to stdout directly.
CLI (internal/cli):
- capability-validation block repeated in apply/check/status/doctor/configcmd (configcmd hardcodes 14 names).
- read-only RunContext construction repeated in status/doctor/check.
statustext and JSON are built by two code paths; text skipsValidateCapabilities.- cloudflared binary path defined 3 times, version parsing twice;
fetchLatestVersionduplicatesFetchLatestCloudflaredVersion; token masking two ways;firstNonEmptyCloudflaredduplicatesfirstNonEmpty. - apply/backup/tunnel/tenant print with raw
fmtand literal glyphs instead ofuihelpers andcmd.OutOrStdout(); fleet has its own JSON encoder and hardcoded exit 2.
Implementation starts only on the owner's go-ahead.
Decisions
- One helper per concern, in the package that already owns it; no new interfaces.
- Output goes through
internal/uiand anio.Writerpassed in (rc.Out), astenant.Manageralready does. - daemon-reload failure policy: warning (the unit write already succeeded; next apply retries).
Design
internal/module/files.go:ensureFile(rc, path, content, mode) (changed bool, err error),systemdReload,enableUnit.UsersConfig.Base(); exportedtenant.GeneratePassword(orinternal/secret).config.ModuleNames()used by distro andIsModuleEnabled, with a test againstdefaultOrder.- CLI:
validateModules(cfg, names),readOnlyRunContext(cmd), status text rendered fromcollectStatus,githubLatestTag(owner, repo), onemaskSecret. RunContext.Out io.Writer; module prints becomeui.WriteBullet(rc.Out, ...).
Changes
internal/module/*,internal/tenant/manager.go,internal/fleet/{ssh,rollout}.go,internal/config/{config,distro}.go,internal/cli/*.
Acceptance criteria
- AC1:
status -o textand-o jsoncome from one collector (test compares module sets). - AC2: module-name lists agree (test fails if any of the four diverge).
- AC3: no
fmt.Printininternal/modulenon-test files; no literal✓✗⚠→outsideinternal/ui. - AC4:
go test ./... -racepasses;apply --dry-runoutput on each profile is unchanged except glyph routing (golden diff reviewed in the PR).
Tasks
- T1: module
files.go+ callers - T2: config module names, home base, password helper (AC2)
- T3: CLI helpers and single status collector (AC1)
- T4: output through ui /
rc.Out(AC3, AC4)
Split into several PRs along T1-T4; each PR keeps go test ./... -race green.
Out of scope
- Behaviour changes beyond reconciling the drifted copies.
Metadata
Metadata
Assignees
Labels
refactoringRefactoringRefactoring
Activity
entelecheia commentedon Nov 9, 2026
Reopened: PR #120 delivered only T1 (shared file and systemd helpers). GitHub closed this issue because the PR body contained the phrase 'does not close #94', which it parsed as a closing keyword. T2-T4 continue; the final PR closes it.