Chrison.SynoSharp 0.1.1-preview.4

This is a prerelease version of Chrison.SynoSharp.
dotnet add package Chrison.SynoSharp --version 0.1.1-preview.4
                    
NuGet\Install-Package Chrison.SynoSharp -Version 0.1.1-preview.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Chrison.SynoSharp" Version="0.1.1-preview.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Chrison.SynoSharp" Version="0.1.1-preview.4" />
                    
Directory.Packages.props
<PackageReference Include="Chrison.SynoSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Chrison.SynoSharp --version 0.1.1-preview.4
                    
#r "nuget: Chrison.SynoSharp, 0.1.1-preview.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Chrison.SynoSharp@0.1.1-preview.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Chrison.SynoSharp&version=0.1.1-preview.4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Chrison.SynoSharp&version=0.1.1-preview.4&prerelease
                    
Install as a Cake Tool

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.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1-preview.4 28 7/24/2026
0.1.0-preview.3 34 7/23/2026
0.1.0-preview.2 34 7/23/2026
0.1.0-preview.1 34 7/23/2026