Skip to content

Phase A reconciler — shares/users/groups, dry-run default (#57)#4

Merged
ChrisonSimtian merged 1 commit into
mainfrom
feat/synosharp-share-user-group-write
May 31, 2026
Merged

Phase A reconciler — shares/users/groups, dry-run default (#57)#4
ChrisonSimtian merged 1 commit into
mainfrom
feat/synosharp-share-user-group-write

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

The IaC vertical on top of the SSH-runner (transport wedge, #3). Per the write-path plan, Phase A.

What

  • Tools/SynoShareTool / SynoUserTool / SynoGroupTool: typed --enum reads + command builders that encode each tool's positional argv once (DSM 7.1). Shared EnumOutput parser (names = non-colon lines after the Listed: header — verified live).
  • Provisioning/Share/User/GroupSpec + SynologyDesiredState; SynologyReconciler: PlanAsync diffs desired vs live, ApplyAsync runs. Output is a SynologyPlan of create/delete/skip actions, each carrying its command + reason.
    • Dry-run by default (like Deploy-Shape.ps1) — ApplyAsync(apply:false) mutates nothing.
    • Never prunes unmanaged resources — deletes only when a spec sets present:false.
    • Passwordless user-create is BLOCKED with a clear reason (can't synouser --add without a password).
  • CLIplan <spec.json> (read-only diff), apply <spec.json> [--confirm] (dry-run unless --confirm).
  • Tests — 5 reconciler tests over a scripted ISshRunner (no NAS needed).

Verification (live NAS, 2026-05-31, zero mutation)

synosharp plan against a mixed spec:

= skip   group users  (already present)
+ create group synosharp-demo  (absent → create)
      $ synogroup --add synosharp-demo
= skip   user homelab  (already present)
= skip   user svc-no-pw  (BLOCKED: create needs a Password)
= skip   share Volume-1  (already present)
+ create share synosharp-test  (absent → create)
      $ synoshare --add synosharp-test 'demo share' /volume1/synosharp-test '' '' '' 1 0
2 change(s) to apply.

Not in this PR

A real apply --confirm against the live box (would create/delete) — deferred to an explicit reversible smoke test. Field-level drift (desc/ACLs) and NFS (synowebapi, on Virtual DSM) are later phases.

🤖 Generated with Claude Code

… default (#57)

The IaC vertical on top of the SSH-runner: typed tool wrappers + a
desired-state reconciler that diffs against live state and emits only the
needed actions, so the non-idempotent syno* CLIs become safe.

- Tools/: SynoShareTool/SynoUserTool/SynoGroupTool — typed `--enum` reads +
  command builders that encode the positional argv once (DSM 7.1). Shared
  EnumOutput parser (names = non-colon lines after the "Listed:" header).
- Provisioning/: Share/User/GroupSpec + SynologyDesiredState; SynologyReconciler
  (PlanAsync diffs, ApplyAsync runs) → SynologyPlan of create/delete/skip actions,
  each carrying its command + reason. Dry-run by default; never prunes unmanaged.
  Passwordless user-create is BLOCKED with a clear reason.
- CLI: `plan <spec.json>` (read-only diff) + `apply <spec.json> [--confirm]`
  (dry-run unless --confirm).
- Tests: 5 reconciler tests over a scripted ISshRunner (no NAS needed).

Verified against the live NAS (2026-05-31): `plan` skipped the 3 existing
resources, planned correct creates for 2 new ones, blocked the passwordless
user — zero mutation (reads only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtian merged commit 9f87606 into main May 31, 2026
1 check passed
@ChrisonSimtian
ChrisonSimtian deleted the feat/synosharp-share-user-group-write branch May 31, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant