Chrison.SynoSharp.Cli 0.1.0-preview.5

This is a prerelease version of Chrison.SynoSharp.Cli.
dotnet tool install --global Chrison.SynoSharp.Cli --version 0.1.0-preview.5
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Chrison.SynoSharp.Cli --version 0.1.0-preview.5
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Chrison.SynoSharp.Cli&version=0.1.0-preview.5&prerelease
                    
nuke :add-package Chrison.SynoSharp.Cli --version 0.1.0-preview.5
                    

SynoSharp

NuGet Downloads ci built with Fallout License: MIT

A C# client for Synology DSM IaC. Sibling to ProxmoxSharp/UnifiSharp β€” but not code-generated: Synology publishes no settings/deploy API schema, so per ADR-0002 this is a hand-written read-API client (now) + an SSH-runner for mutations (later).

dotnet add package Chrison.SynoSharp
flowchart LR
  APP["🧩 homelab engine / CLI"] -->|"read / discover"| WEB["🌐 DSM Web API<br/>SYNO.API.Auth β†’ entry.cgi β†’ SYNO.Core.*"]
  APP -. "mutations (write phase)" .-> SSH["πŸ” SSH-runner<br/>syno* CLI + synowebapi"]
  WEB --> SNAP["πŸ“Š SynologySnapshot"]
  SSH --> NAS["πŸ—„οΈ DSM 7.1 Β· DS1813+"]
  WEB --- NAS
  classDef future fill:#f3f4f6,stroke:#9ca3af,color:#6b7280;
  class SSH future;

Approach

  • Read / discover β†’ the DSM Web API (SYNO.API.Auth β†’ entry.cgi β†’ SYNO.Core.*), returning a structured SynologySnapshot. (This repo.)
  • Mutations (shares, NFS, users, network) β†’ an SSH-runner over the on-box syno* CLI + synowebapi (added with the write phase). The SYNO.Core.* endpoints are undocumented/version-fragile β€” pinned to DSM 7.1 (the DS1813+ is EOL there).

Projects

Project What
src/SynoSharp/ The client β€” SynologyApiClient (Web-API read), SynologyDiscovery β†’ SynologySnapshot, Ssh/ (the SSH-runner), Tools/ (typed synoshare/synouser/synogroup wrappers), Provisioning/ (specs + reconciler). SemVer.
src/SynoSharp.Cli/ synosharp dotnet tool β€” discover, ssh-check, plan, apply.
tests/SynoSharp.Tests/ Unit (quoting + reconciler) + skippable live tests (Web-API + SSH).

Build / use

Built with Fallout (Chris's C#/.NET build system, a NUKE successor). Requires the .NET 10 SDK and GITHUB_PACKAGES_PAT (a PAT with read:packages on the Fallout-build org β€” restores Fallout.*, see nuget.config).

./build.sh              # default: Test (Compile + Test); ./build.sh Pack β†’ Chrison.* nupkgs
export SYNOLOGY_BASE_URL=https://nas:5001 SYNOLOGY_USER=… SYNOLOGY_PASSWORD=… SYNOLOGY_VERIFY_TLS=false
synosharp discover     # JSON snapshot: model, serial, DSM version, shares, users
synosharp ssh-check    # prove the SSH-runner: login + sudo-to-root + read-only `synoshare --enum`

The SSH-runner reuses SYNOLOGY_USER/SYNOLOGY_PASSWORD (the account also supplies the sudo password β€” syno* need root) and derives the host from SYNOLOGY_BASE_URL; override with SYNOLOGY_SSH_HOST/SYNOLOGY_SSH_PORT/SYNOLOGY_SSH_KEY. DSM 7 disables direct root SSH, so the runner logs in as an admin user and sudo -S (password over stdin, never in the command line), running tools through env PATH=/usr/syno/sbin:… since sudo's secure_path excludes the syno dirs.

Packages publish to nuget.org (public) under the Chrison.* prefix (Chrison.SynoSharp, Chrison.SynoSharp.Cli) via Trusted Publishing (OIDC β€” no stored key), like the siblings: prerelease on push to main, stable on v* tag. Assembly name/namespace stay SynoSharp, so using SynoSharp; is unchanged.

Status

Read/discover β€” verified against the live NAS (2026-05-31, DS1813+ / DSM 7.1.1-42962). discover returns model, serial, DSM version, share names and user names (SYNO.Core.System / Share / User). The SYNO.Core.* reads are defensive (degrade to empty on shape mismatch).

SSH-runner transport β€” verified against the live NAS (2026-05-31). ssh-check proves the full stack end-to-end (SSH login β†’ sudo-to-root β†’ on-box syno*): synoshare --enum ALL lists the live shares with zero mutation. The runner (ISshRunner/SshRunner over SSH.NET) + structured SynologyCommand (shell-quoted argv) are the transport for the write path.

Write path (Phase A) β€” reconciler for shares/users/groups, dry-run by default. Desired-state specs (ShareSpec/UserSpec/GroupSpec) are diffed against live state by SynologyReconciler β†’ a SynologyPlan of create/delete/skip actions; each carries the exact synoshare/synouser/synogroup command. ApplyAsync(apply:false) is a dry-run (the default). Verified against the live NAS (2026-05-31): plan correctly skipped existing resources, planned creates for new ones, and blocked a passwordless user create β€” zero mutation (reads only).

synosharp plan  spec.json              # diff vs live β†’ dry-run plan (read-only)
synosharp apply spec.json              # still a dry-run…
synosharp apply spec.json --confirm    # …only this mutates

The reconciler does existence + field reconciliation: create-if-missing / delete-if-present:false / modify-on-drift / skip-if-in-sync, and never prunes unmanaged resources. Field drift is checked for share/group Description and user FullName/Email (read via --get/--descget, set via --setdesc/--descset/--modify); empty/null spec fields are unmanaged (never clobbered), and expired is preserved. Share deletes keep data by default (DSM shares are btrfs subvolumes); set ShareSpec.DeleteData = true for a destructive synoshare --del TRUE. Next: list-valued fields (share ACLs, group membership), then NFS exports via synowebapi β€” last, highest-risk, prove on Virtual DSM (needs an x86/KVM host). See the write-path plan.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.0-preview.5 89 8/3/2026
0.1.0-preview.4 79 7/24/2026
0.1.0-preview.3 78 7/23/2026
0.1.0-preview.2 60 7/23/2026
0.1.0-preview.1 73 7/23/2026