Skip to content

ci: add PR quality gates (fmt/clippy/test/build) [#230] - #2

Merged
MichaelTaylor3d merged 1 commit into
mainfrom
ci/add-quality-gates
Jul 4, 2026
Merged

ci: add PR quality gates (fmt/clippy/test/build) [#230]#2
MichaelTaylor3d merged 1 commit into
mainfrom
ci/add-quality-gates

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

What

Adds .github/workflows/ci.yml — the professional PR-gated CI for this Rust workspace, triggered on: pull_request (to main) and push to main.

Jobs (stable name: = required-check contexts):

  • Rustfmtcargo fmt --all -- --check
  • Clippycargo clippy --workspace --all-targets -- -D warnings
  • Test + coveragecargo llvm-cov --workspace --summary-only (runs the whole workspace test suite AND measures line coverage in one instrumented build)

Notes

  • No wasm build step needed: the digstore guest wasm is vendored (vendor/digstore_guest.wasm) and wired via .cargo/config.tomlDIGSTORE_GUEST_WASM, so the checkout already carries the artifact (CLAUDE.md §3.5).
  • Coverage is measure-only (non-blocking) for now — the ≥80% floor is tracked separately (feat(dig-node): peer provider-snapshot mTLS RPC + concrete NeighbourhoodProbe #157). Raising the gate is a one-line change (--fail-under-lines 80).
  • Verified locally: fmt clean, clippy clean with -D warnings, 71 tests pass.

Version

Patch bump dig-node-service 0.4.0 → 0.4.1 (chore/ci, no behaviour change) to satisfy the version-increment gate.

@MichaelTaylor3d
MichaelTaylor3d merged commit f73fafe into mainJul 4, 2026
5 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the ci/add-quality-gates branch July 4, 2026 10:55
MichaelTaylor3d added a commit that referenced this pull request Jul 10, 2026
Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d added a commit that referenced this pull request Jul 10, 2026
Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d added a commit that referenced this pull request Jul 13, 2026
…residual)
Close the LOW-but-real control-token custody residual an adversarial verify
found: `load_or_create_token_at` trusted a non-empty pre-existing token file
WITHOUT checking who owns it. An unprivileged local user who plants a KNOWN
token in the machine-wide state dir (a %PROGRAMDATA% squat, or the narrow
window during a service harden) would have the LocalSystem daemon read + trust
it, learning the control token → full local `control.*` node control (local
privilege escalation).
Fix: before trusting an existing token, verify its file OWNER; a foreign-owned
token is deleted + regenerated, never returned. Trust rule (pure, unit-tested):
- Windows: owner SID SYSTEM (S-1-5-18) / Administrators (S-1-5-32-544) always;
a NON-service run also accepts the current process user's SID (dev tokens in
the legacy per-user dir); a SERVICE run requires SYSTEM/Administrators.
- Unix: owner uid 0 (root) always, else owner == current euid AND mode 0600.
Owner read via the existing Get-Acl helper (`dir_owner_sid` renamed to
`path_owner_sid`, now used for files too) on Windows and `stat` on Unix; euid
via a dependency-free probe file. Layered beneath the §7.3a state-dir hardening
(which already purges a squatter-owned dir on a service run — item #2 landed in
ee33f1b) as defense-in-depth: it also guards the non-hardened dev path and any
harden gap. Coherent with the installer daemon_dir.rs trust model (dir owner
SYSTEM/root + interactive-user read).
TDD: pure trust-decision helpers + FS-decision + regeneration tests (red→green,
Windows path verified locally on win32; unix-gated tests run in CI). SPEC.md
§7.3 documents the owner-verification requirement.
Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d added a commit that referenced this pull request Jul 13, 2026
…(#501, #389) (#32)
* feat: machine-wide control-token state dir + dig-node open handler (#501, #389)
Deliverable A (#501): decouple the control token + paired-token store from the
per-user config dir into a machine-wide, identity-INDEPENDENT state dir so the
daemon (which may run as a service under a different OS account, e.g. Windows
LocalSystem) and the operator CLI resolve the SAME token file.
- Add `state::state_dir()`: Windows `%PROGRAMDATA%\DigNode`, Linux `/var/lib/dig-node`
(fallback `/etc/dig-node`), macOS `/Library/Application Support/DigNode`; env override
`DIG_NODE_STATE_DIR`; legacy per-user fallback for a non-service dev run (back-compat).
- Move ONLY control-token + paired-tokens.json there; the bulk per-user `.dig` cache +
config.json stay exactly as-is (#96).
- Security: created dir/token get a restrictive ACL (Unix 0700 dir / 0600 file; Windows
SYSTEM+Admins full + the installing user read, inheritance removed) — never world-readable.
The ACL is applied only on FRESH create so a SYSTEM/root service re-run cannot clobber the
installer's install-user grant. `dig-node install` pre-creates the dir as the interactive
user; the service self-identifies via DIG_NODE_RUN_CONTEXT.
- `dig-node pair` reads the token read-only (never mints a phantom the node won't trust) and
surfaces a precise service-vs-user remedy; the control.* 401 names the exact path + remedy.
Deliverable B (#389): implement `dig-node open <chia://… | urn:dig:chia:…>` (+ --json),
the OS scheme-handler target. Strictly validates (only chia/urn-dig schemes; rejects
file:/javascript:/data:, shell metacharacters, path traversal, non-64-hex store refs),
then opens the default browser at the node's local serve URL via a no-shell launcher
behind an injectable trait.
Version: 0.26.0 -> 0.27.0 (minor; additive + back-compat).
Refs #501 #389
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(state): grant creator full ACL, derive Outcome Debug, doc state-dir in SPEC
- Windows ACL: grant the CREATING user full (not read-only) on the fresh state dir —
the same process that creates the dir must be able to WRITE the token it mints
(dev/self-create path failed with Access Denied otherwise). Security property held:
every OTHER local user is still denied. Simplify windows_restrict_dir (dirs only).
- derive Debug on cli::Outcome (needed for the open.rs error-path test).
- Map io::ErrorKind::InvalidInput -> USAGE exit (a rejected `dig-node open` link).
- SPEC.md: new §7.3a (state-dir location/resolution/ACL/threat-model), §8.5
(`open` scheme-handler contract), and control-token/paired-token/conformance/
security updates to the state-dir model.
Refs #501 #389
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(state): clippy cloned-ref-to-slice in state_dir test (CI --all-targets)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(state): gate MACHINE_FOLDER to win/macos (dead_code on Linux -D warnings)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(state): harden+verify machine state dir on service run (close ProgramData squat P0)
The control token grants FULL local control of the node, so its machine-wide
state dir (%PROGRAMDATA%\DigNode) must never be readable by Users/Everyone. On
Windows %PROGRAMDATA% lets BUILTIN\Users create subfolders, so a low-priv user
could pre-create C:\ProgramData\DigNode, become CREATOR OWNER (implicit
WRITE_DAC), and control the dir the node writes the control token into — a local
privilege escalation.
Previously choose_state_dir returned a pre-existing machine dir via the `exists`
branch WITHOUT hardening it, and ensure_dir_restricted early-returned on any
existing dir, so a squatted dir was trusted as-is.
Fix (coherent with dig-installer's daemon_dir.rs contract): on a SERVICE run,
before the token is written/read, harden+readback-verify the resolved MACHINE
state dir — setowner *S-1-5-18 (SYSTEM) -> /reset (purge foreign ACEs) ->
/inheritance:r + grant {SYSTEM:F, Administrators:F, and only-if-discoverable the
interactive install-user:R} -> parse `icacls`/Get-Acl readback and assert no
Users/Everyone/Authenticated-Users/Anonymous ACE, owner=SYSTEM, inheritance off,
no unexpected principal. A squatter-owned pre-existing dir is purged. FAIL
CLOSED: if the dir cannot be secured, the node refuses to serve control from it
(ephemeral dir + in-memory unauthorizable token), never writing the token into
an unsecured dir.
Grant principal comes from the CURRENT PROCESS TOKEN (whoami /user), never the
spoofable %USERNAME% env, and well-known group SIDs are rejected. A SYSTEM
service preserves an installer-set interactive read grant only on a TRUSTED
(SYSTEM/Administrators-owned) dir. The CLI (non-service) never hardens — it only
reads an existing machine dir, else the legacy per-user dir (unchanged). Dev
self-create keeps the creating user FULL so it can write the token it mints.
Pure argv builders, the SID reject, and the readback-assertion parser are
unit-tested (real ACL is not exercised in CI). SPEC.md §7.3a documents the
contract.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(state): verify control-token file owner before trusting it (#501 residual)
Close the LOW-but-real control-token custody residual an adversarial verify
found: `load_or_create_token_at` trusted a non-empty pre-existing token file
WITHOUT checking who owns it. An unprivileged local user who plants a KNOWN
token in the machine-wide state dir (a %PROGRAMDATA% squat, or the narrow
window during a service harden) would have the LocalSystem daemon read + trust
it, learning the control token → full local `control.*` node control (local
privilege escalation).
Fix: before trusting an existing token, verify its file OWNER; a foreign-owned
token is deleted + regenerated, never returned. Trust rule (pure, unit-tested):
- Windows: owner SID SYSTEM (S-1-5-18) / Administrators (S-1-5-32-544) always;
a NON-service run also accepts the current process user's SID (dev tokens in
the legacy per-user dir); a SERVICE run requires SYSTEM/Administrators.
- Unix: owner uid 0 (root) always, else owner == current euid AND mode 0600.
Owner read via the existing Get-Acl helper (`dir_owner_sid` renamed to
`path_owner_sid`, now used for files too) on Windows and `stat` on Unix; euid
via a dependency-free probe file. Layered beneath the §7.3a state-dir hardening
(which already purges a squatter-owned dir on a service run — item #2 landed in
ee33f1b) as defense-in-depth: it also guards the non-hardened dev path and any
harden gap. Coherent with the installer daemon_dir.rs trust model (dir owner
SYSTEM/root + interactive-user read).
TDD: pure trust-decision helpers + FS-decision + regeneration tests (red→green,
Windows path verified locally on win32; unix-gated tests run in CI). SPEC.md
§7.3 documents the owner-verification requirement.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto 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

@MichaelTaylor3d