v0.1.0 enhancements: local-testing setup, release/packaging pipeline, install docs, login agent, and test coverage#7
Open
CraZySacX wants to merge 8 commits into
Open
v0.1.0 enhancements: local-testing setup, release/packaging pipeline, install docs, login agent, and test coverage#7CraZySacX wants to merge 8 commits into
CraZySacX wants to merge 8 commits into
Conversation
Introduce a tracked dev/ directory and a fish helper so debug builds of salusd/salusc can be exercised from the project tree without colliding with a production install on the same machine. - dev/salusd.toml, dev/salusc.toml: base config (relaxed key_timeout=300 so the in-memory key does not auto-clear during manual testing) - dev/.gitignore: track only the configs; ignore the runtime db, log, socket - scripts/dev_env.fish: salusd-dev / salusc-dev wrappers that pass the config/db/log/socket paths as explicit CLI flags, pointing everything at dev/ - README: new "Local testing (debug builds)" section explaining socket isolation (the default Linux abstract-namespace socket is shared by every install, so a file socket under dev/ avoids binding the same name) and that the db/config/log paths are CLI-only and must be redirected with -d/-c/-t Also bump bon 3.9.2 -> 3.9.3 and reformat the salusd tracing-subscriber feature list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #7 +/- ##
===========================================
+ Coverage 44.09% 63.79% +19.69%
===========================================
Files 22 35 +13
Lines 1313 2831 +1518
===========================================
+ Hits 579 1806 +1227
- Misses 734 1025 +291 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Introduce a tag-driven release/distribution pipeline modeled on the sister projects (moshpit for AUR/dist/packaging, cargo-matrix for the crates.io publish, barto for the Homebrew tap), scaled to salus's single-package layout (salusd daemon + salusc client). - xtask crate: `cargo xtask dist salusd|salusc` generates shell completions, man pages, licenses, and (for salusd) the systemd unit and example config. publish = false + cargo-matrix skip-package. - packaging/: source `salus` and prebuilt static-musl `salus-bin` PKGBUILDs, nfpm DEB/RPM configs (x86_64 + aarch64), a systemd user service for salusd, a Homebrew formula template, and a .SRCINFO helper. - docker/ + Cross.toml: cross-rs musl images carrying cmake/clang for aws-lc-sys. - .github/workflows/release.yml: build (musl) + build-macos, GitHub release, crates.io publish (libsalus -> salusd -> salusc), PKGBUILD update PR, AUR publish, signed apt/rpm repo, Homebrew tap update; publishing gated off `-rc` tags. Plus test-aur-publish.yml for manual AUR connectivity checks. - crates.io prep: pin the libsalus path dep to a version in salusd/salusc so the crates are publishable. - scripts: run_install.fish (cargo install to ~/.cargo/bin) and run_musl.fish (blackdex/rust-musl build), wired into run_all.fish with --no-install/--no-musl/--unstable; fuzz crate gains a forwarding `unstable` feature. - docs: README "Installation"/"Releasing" sections; CLAUDE.md commands and final-verification note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The release workflow and the source PKGBUILD invoke `cargo xtask dist`, but salus had no `[alias] xtask` (unlike moshpit), so the step failed with "no such subcommand: xtask". Add .cargo/config.toml defining the alias so `cargo xtask` resolves on CI and during makepkg builds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The release workflow and Arch PKGBUILD called `cargo xtask dist`, which only resolves via the `[alias]` in .cargo/config.toml. That dependency on cargo config discovery is fragile in CI (the macOS build job failed with "no such command: xtask"). Call the workspace binary directly with `cargo run --locked -p xtask -- dist` so the step never depends on alias resolution. The .cargo alias stays for local dev convenience. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expand the README with per-platform install/run instructions (AUR, Debian/Ubuntu apt, Fedora/RHEL dnf, cargo, Homebrew), modeled on the moshpit README, and fix two packaging defects found while writing them. - systemd unit path: packages install the binary at /usr/bin/salusd, but salusd.service pointed ExecStart at %h/.cargo/bin/salusd, so a package-installed `systemctl --user enable --now salusd` started a unit referencing a binary that isn't there. Point ExecStart at /usr/bin/salusd and document the cargo-install path adjustment. - service lifecycle on install/upgrade: add post-install guidance scriptlets for DEB/RPM (nfpm postinstall) and AUR (.install hooks). salusd is a per-user service, so root-run package scripts cannot stop or restart it; the scriptlets print the manual `systemctl --user daemon-reload && restart` + re-unlock steps instead of faking a root-side restart. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce an ssh-agent-style login agent and an enrollment workflow that make unlocking convenient without weakening the Shamir guarantee: of the `threshold` shares needed to unlock, `threshold - 1` are stored in the OS keyring (auto-unlocked at login) and the final share is sealed behind a passphrase, so the auto-accessible material alone stays below threshold. Default behavior is unchanged — without enrollment, `salusc unlock` still prompts for every share. - salus-agent crate (4th workspace member, lib + bin): loads enrolled share sets from the OS keyring at login and serves them to the client over its own IPC socket, with a per-set, generation-guarded passphrase cache (default 3600s TTL; 0 disables). A systemd user unit launches it. - keystore (in salus-agent, reused by salusc): keyring layout (sets registry, shared `auto-share-N`, per-set `<set>/final-blob`) and argon2id + AES-256-GCM seal/unseal of the single passphrase share. Multiple named sets are supported (`enroll --name`), each adding a distinct passphrase share over the shared auto shares so the keyring never holds >= threshold. - libsalus: AgentAction/AgentResponse protocol, `agent_socket_name` (SALUS_AGENT_SOCKET), `UnlockTimeout`, and `Action::Lock`. - salusd: `unlock` honors a hold duration (default / N seconds clamped to 24h / forever); new `Action::Lock` clears the key and bumps the unlock generation so a pending auto-clear timer becomes a no-op. - salusc: `enroll`/`forget`/`enroll-status`; `unlock` pulls the auto shares from the agent and prompts only for the passphrase, falling back to manual share entry when the agent is absent; adds `unlock --set/--for`, `lock`, and `--agent-socket-path`. - packaging: xtask `dist salus-agent`, systemd unit, example config, nfpm DEB/RPM (x86_64 + aarch64), AUR `salus` + `salus-bin`, Homebrew, and the release workflow (build/dist/checksums + publish order libsalus -> salus-agent -> salusd -> salusc). - scripts: salus-agent-dev wrapper in dev_env.fish; run_install/run_musl build the third binary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The keyring `sync-secret-service` feature pulls in
dbus-secret-service -> dbus -> libdbus-sys, which links the system
libdbus via pkg-config. The Linux CI runners lack libdbus-1-dev, so the
build script panicked ("Package dbus-1 was not found"). The static MUSL
release Dockerfiles install pkg-config but not libdbus-1-dev, so the
release build would have failed the same way on its next run.
Switch to keyring's pure-Rust Secret Service backend
(async-secret-service + async-io + crypto-rust), which speaks the D-Bus
wire protocol via zbus and needs no system or C dependency. This fits a
tool that ships fully-static MUSL binaries and per-distro packages,
rather than patching a single CI job with an apt install.
The async-io runtime (not tokio) is used so keyring's internal block_on
does not panic with a nested-runtime error when its synchronous Entry
API is called from within the tokio runtime (AgentState::load at startup
and the spawned handlers). The public keyring API is unchanged, so no
salus-agent code changes are needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov flagged PR #7 at 24.8% patch / 35.87% project coverage, below the 50% gate, mostly from the new salus-agent crate and daemon/client plumbing that shipped with little or no test coverage. Make handlers unit-testable by relaxing the sender bound from `SendHalf + Unpin` to `tokio::io::AsyncWrite + Unpin` in both the agent and daemon handlers; interprocess's `SendHalf` already implements tokio `AsyncWrite`, so production callers are unaffected while tests can drive a handler with a `Vec<u8>` and decode the response. Add a persistent in-memory keyring backend (test_keyring.rs) since the stock `keyring::mock` does not survive across the fresh `Entry::new` calls keystore makes per operation. Extract the pure `parse_set_choice` helper out of the stdin-bound `choose_set` so the selection logic can be tested. New tests cover the keystore enroll/forget/load lifecycle, AgentState cache/generation/lock logic, agent and daemon handler dispatch, logging directives, config loading/defaults, CLI flags, and libsalus socket resolution. Local line coverage rises from ~36% to ~60%, clearing the gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
This branch carries the v0.1.0 enhancements: an isolated local-testing setup for debug builds, a full tag-driven release/distribution pipeline, per-platform package install documentation with the service-lifecycle fixes it surfaced, an ssh-agent-style login agent with share enrollment, and a CI/packaging fix to drop the system libdbus build dependency.
1. Release pipeline (AUR, DEB/RPM, Homebrew, crates.io, systemd)
A tag-driven release pipeline modeled on the sister projects — moshpit (AUR/dist/packaging), cargo-matrix (crates.io publish), barto (Homebrew tap) — scaled to salus's single-package layout (
salusddaemon +saluscclient).cargo xtask dist salusd|saluscgenerates bash/zsh/fish completions, man pages, licenses, and (forsalusd) the systemd unit and example config.publish = false+cargo-matrix skip-package.salusPKGBUILD and a prebuilt static-muslsalus-binPKGBUILD, nfpm DEB/RPM configs (x86_64 + aarch64), asalusdsystemd user service, a Homebrew formula template, and a.SRCINFOhelper.aws-lc-sys.libsalus→salusd→salusc), PKGBUILD-update PR, AUR publish, signed apt/rpm repo, Homebrew tap update. Publishing jobs are gated off-rctags so anvX.Y.Z-rc*tag is build-only. Plustest-aur-publish.ymlfor manual AUR connectivity checks.libsaluspath dep to a version insalusd/saluscso the crates are publishable.run_install.fish(cargo install to~/.cargo/bin) andrun_musl.fish(blackdex/rust-musl build), wired intorun_all.fishwith--no-install/--no-musl/--unstable; the fuzz crate gains a forwardingunstablefeature.Required repository secrets (before the first tag)
CRATES_IO_TOKEN(crates.io),AUR_SSH_PRIVATE_KEY(AUR),HOMEBREW_TAP_TOKEN(Homebrew tap), andPACKAGES_REPO_TOKEN+PACKAGES_GPG_PRIVATE_KEY+PACKAGES_GPG_KEY_ID(signed apt/rpm repo). Companion repos:rustyhorde/homebrew-salusandrustyhorde/salus-packages.2. Isolated local-testing setup for debug builds
Adds a tracked
dev/directory and a fish helper so debug builds ofsalusd/salusccan be exercised from the project tree without colliding with a production install on the same machine.salus.sock) shared by every install, so a debug daemon would bind the same name as a running production daemon. Pointing the socket at a file path underdev/switchessocket_targetto itsFilebranch, isolating the dev pair.-d/-c/-t), not read from env or the TOML file, so without-da debug daemon reads/writes the production DB. The helper always redirects them intodev/.Changes:
dev/salusd.toml,dev/salusc.toml(relaxedkey_timeout = 300),dev/.gitignore(tracks only configs),scripts/dev_env.fish(salusd-dev/salusc-devwrappers), and a README "Local testing (debug builds)" section. Minor maintenance: bumpbon3.9.2 → 3.9.3 and reformat thesalusdtracing-subscriberfeature list.3. Package install docs + service-lifecycle fixes
Expands the README "Installation" section into per-platform guides modeled on the moshpit README — Arch/AUR (
salussource +salus-binprebuilt), Debian/Ubuntu (signed apt repo, direct.deb,dpkg, upgrade/removal), Fedora/RHEL (signed dnf repo, direct.rpm), cargo, and Homebrew — and fixes two packaging defects found while writing them./usr/bin/salusd, butsalusd.servicepointedExecStartat%h/.cargo/bin/salusd, so a package-installedsystemctl --user enable --now salusdreferenced a binary that isn't there.ExecStartnow targets/usr/bin/salusd, with a comment forcargo installusers (binary at~/.cargo/bin/salusd).salusdis a per-user service by design (per-user store, config, and socket), so root-run package scripts cannot stop or restart it the way a system service could — and an auto-restart would clear the in-memory key and lock the store. Added DEB/RPMpostinstallscriptlets (nfpmoverrides) and AURsalusd.installhooks that print the manualsystemctl --user daemon-reload && restart+ re-unlock guidance instead. The release workflow carries the new.installsidecars automatically (update-pkgbuildsuploads all ofpackaging/arch/;aur-publishcopies every sidecar).cargo installpath caveat.4. salus-agent login agent, share enrollment, unlock duration, and lock
An ssh-agent-style login agent and an enrollment workflow that make unlocking convenient without weakening the Shamir guarantee: of the
thresholdshares needed to unlock,threshold - 1are stored in the OS keyring (auto-unlocked at login) and the final share is sealed behind a passphrase, so the auto-accessible material alone stays below threshold. Default behavior is unchanged — without enrollment,salusc unlockstill prompts for every share.auto-share-N, per-set<set>/final-blob) and argon2id + AES-256-GCM seal/unseal of the single passphrase share. Multiple named sets are supported (enroll --name), each adding a distinct passphrase share over the shared auto shares so the keyring never holds ≥ threshold.AgentAction/AgentResponseprotocol,agent_socket_name(SALUS_AGENT_SOCKET),UnlockTimeout, andAction::Lock.unlockhonors a hold duration (default / N seconds clamped to 24h / forever); newAction::Lockclears the key and bumps the unlock generation so a pending auto-clear timer becomes a no-op.enroll/forget/enroll-status;unlockpulls the auto shares from the agent and prompts only for the passphrase, falling back to manual share entry when the agent is absent; addsunlock --set/--for,lock, and--agent-socket-path.dist salus-agent, systemd unit, example config, nfpm DEB/RPM (x86_64 + aarch64), AUR + Homebrew, release publish orderlibsalus → salus-agent → salusd → salusc, and asalus-agent-devwrapper / third-binary builds in the helper scripts.5. Drop the system libdbus build dependency (CI/packaging fix)
The login agent pulled in
keyringwith thesync-secret-servicefeature, which links the systemlibdbus(dbus-secret-service → dbus → libdbus-sys, resolved viapkg-config). The Linux CI runners lacklibdbus-1-dev, so the build script panicked (Package dbus-1 was not found); the static-musl release Dockerfiles installpkg-configbut notlibdbus-1-dev, so the release build would have failed the same way.Switched
keyringto its pure-Rust zbus backend (async-secret-service+async-io+crypto-rust), which speaks the D-Bus wire protocol with no system or C dependency — the right fit for a tool shipping fully-static MUSL binaries and per-distro packages, rather than patching one CI job with an apt install. Theasync-ioruntime (nottokio) is used so keyring's internalblock_ondoes not panic with a nested-runtime error when its synchronousEntryAPI is called from within the tokio runtime. The public keyring API is unchanged, so nosalus-agentcode changes were needed.6. Test coverage for the new agent crate and handlers
Codecov flagged this PR at 24.8% patch / 35.87% project coverage (50% gate), almost entirely from the new
salus-agentcrate and the daemon/client plumbing landing untested. Added unit tests that match the repo's inline#[cfg(test)]conventions and lift local line coverage from ~36% to ~60%.senderbound fromSendHalf + Unpintotokio::io::AsyncWrite + Unpinin both the agent and daemon handlers. interprocess'sSendHalfalready implements tokioAsyncWrite, so production callers are unaffected, while tests drive a handler with aVec<u8>sender and decode the response bytes.salus-agent/src/test_keyring.rs) — the stockkeyring::mockbuilds a fresh, non-persistent credential perEntry::new, but keystore opens a newEntryper operation, so writes never round-trip. A customCredentialBuilderover a process-shared map (thekeyring::credentialtraits are public) fixes this; aguard()helper installs it once, clears it, and serializes keyring tests.choose_setintoparse_set_choiceso it can be unit-tested.AgentStatecache/generation/lock logic, agent + daemon handler dispatch, logging directives, config loading/defaults, CLI flags, and libsalus socket resolution. Highlights: keystore 26%→97%, agent store 0%→96%, both handlers 0%→~66%, libsalus/lib.rs 44%→91%. The remaining gap issalusc/src/inter/mod.rs(socket/stdin UI), left for an integration pass.Verification
cargo xtask dist salusd|salusc|salus-agentproduces the expected completions/man pages/licenses/systemd units;libsaluspackages cleanly; both release workflows parse;gen_srcinfo.pyoutput is clean.scripts/run_all.fish --no-fuzz --no-musl --no-install— all tests pass (97 across the workspace), all steps OK (including nightly clippy with-Dwarnings);cargo llvm-covreports ~60% line coverage, up from ~36%.cargo tree -i libdbus-sysis empty — the C dbus stack is out of the build graph (the lockfile still listsdbus-secret-serviceonly becauseCargo.lockrecords the union of a crate's optional deps).dev/salus.sockand createddev/salusd.redb+dev/salusd.log; production paths under~/.config/salusd/and~/.local/share/salusd/were never touched.sh -n; nfpm YAMLs parse. (nfpmisn't installed locally, so a built.deb/.rpmwas not inspected — worth doing before the first tag along with the static-muslaws-lc-rsbuild viascripts/run_musl.fish.)🤖 Generated with Claude Code