feat(backends): filesystem + DSM install backends - #2
Closed
albedosehen wants to merge 1 commit into
Closed
Conversation
Wires the InstallBackend trait surface for both targets rota's first operator (kushtaka.ai on a Synology DSM) needs. FilesystemInstall — writes four files in the configured directory under the certbot naming convention so existing reload scripts work unchanged: <id>.crt (leaf), <id>.chain.crt (intermediate chain), <id>.fullchain.crt (leaf + chain concatenated), <id>.key (private key, mode 0600). Cert files are 0644. Each artifact is written via write-temp + fsync + rename so a crash mid-install can never expose a half-written cert to the consuming service. Parent directory is created if missing for ergonomics; existing files are overwritten idempotently. DsmInstall — shells out to `synowebapi --exec api=SYNO.Core.Certificate` to import certs into DSM's certificate panel. Two-step flow: list existing certs and find the one whose `desc` matches our configured description (so re-imports update in place rather than create duplicates), then call import with the optional `id=<existing>`. DSM reloads its own nginx as part of import. Cert/chain/key are staged into a per-install tempdir; tests inject a fixed staging directory and a stub binary path to assert command construction without a real DSM. Dispatch in `backends::build_from_config` now matches both InstallSpec variants and returns concrete trait objects; the bundle's `install` field is no longer always None. Tests (10 new, 18 total in workspace): - filesystem: file presence + modes (0644/0600), fullchain ordering, missing-directory creation, overwrite idempotency, concat_pem newline edge cases - dsm: stage produces three files with correct modes, list response parses (with + without `data` block), import error envelope - config: filesystem InstallSpec variant round-trips
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1 (namecheap CA + registrar). Marked draft until the parent merges; will retarget to
mainafterward.Summary
Lands the two install backends rota's first operator needs: plain filesystem (any nginx/Caddy/HAProxy/rustls consumer) and Synology DSM (example.com's actual host).
FilesystemInstall
Writes four files in the configured directory using the certbot naming convention so existing reload scripts work unchanged:
<id>.crt— leaf cert<id>.chain.crt— intermediate chain only<id>.fullchain.crt— leaf + chain concatenated<id>.key— private key (mode 0600); cert files are 0644Each artifact goes through
write to .tmp.<n>→fsync→renameso a crash mid-install can never leave a half-written file visible to the consuming service. Parent directory is created if missing for ergonomics; existing files overwrite idempotently.DsmInstall
Shells out to
synowebapi --exec api=SYNO.Core.Certificate:method=list— find the existing entry whosedescmatches the configured description.method=importwith the staged paths and optionalid=<existing>so re-imports update in place rather than create duplicates. DSM reloads its own nginx as part of import.synowebapionly exists on a running DSM box, so the binary call itself is exercised on the host; CI tests cover the JSON parsing (list/import response shapes) and the staging step (file presence + modes).Dispatch
backends::build_from_confignow matches bothInstallSpecvariants and returns concrete trait objects. TheCertBackends.installfield is no longer alwaysNone.Test plan
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscleancargo test --workspace— 18 passing (10 new)concat_pemnewline edge casesstage()writes three files with correct modes, list response parses (with + withoutdata), import-error envelope surfacesInstallSpecvariant round-tripsWhat's not in this PR