Skip to content

feat(serve): HTTPS on dig.local (127.0.0.2:443) + live leaf rotation (#624)#41

Merged
MichaelTaylor3d merged 1 commit into
mainfrom
feat/624-https-serve
Jul 16, 2026
Merged

feat(serve): HTTPS on dig.local (127.0.0.2:443) + live leaf rotation (#624)#41
MichaelTaylor3d merged 1 commit into
mainfrom
feat/624-https-serve

Conversation

@MichaelTaylor3d

@MichaelTaylor3d MichaelTaylor3d commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #624 — local HTTPS for dig.local (the #620 epic, consuming dig-cert #622 v0.1.0)

Serve the SAME local content router over TLS on 127.0.0.2:443 (https://dig.local), plus a best-effort [::1]:443 IPv6-loopback sibling (§5.2), beside the kept plaintext :80 listener. No plaintext consumer breaks — this is additive.

How it pins dig-cert v0.1.0 (release-first, §4.1)

dig-node-service git-deps dig-cert = { git = ".../dig-cert", tag = "v0.1.0" } — the released tag, never main. The rustls ServerConfig is built with dig_cert::load_server_config (a hot-reloadable ReloadableCertResolver). rustls is pinned byte-identical (0.23, ring, no aws-lc) so exactly one CryptoProvider installs.

Rotation (live reload, no anchor auto-rotate)

The node is the runtime rotation OWNER but delegates the HOW to dig-cert's RenewalManager. A maintain pass at service start + once daily re-issues the leaf from ca.key at <30d remaining, atomically swaps leaf.{key,crt}, and fires resolver.reload() so the running listener presents the new leaf without a restart or dropped connections. The CA trust anchor is NEVER auto-rotated — only ca_renewal_due is reported; anchor rotation is the installer-coordinated dig-cert rotate_ca.

Cross-verify handling (from the #622 review note)

dig-cert's resolver does not cross-verify the leaf key vs cert on reload, but its RenewalManager is safe (reload only after both atomic writes; a torn read keeps the previous cert). This PR uses dig-cert's RenewalManager directly rather than a bespoke file-watcher, so the mismatch window never opens.

Fail-soft when no CA/leaf (installer #623 not yet run)

crate::tls::load_https_material returns None (⇒ plaintext only, informational log) when leaf.{crt,key} are absent/unloadable. HTTPS is never a hard requirement to start — the :443 bind is best-effort like :80.

Version

0.32.00.33.0 (feat → minor).

Tests (gh pr checks after CI)

  • config: dig_local_https_addr = 127.0.0.2:443, v6 = [::1]:443, both None when disabled.
  • tls: fail-soft None when no leaf; Some + reloadable when a leaf is present.
  • tests/https_serve.rs (e2e): a client trusting the per-machine CA gets the content over TLS; a live rotation swaps the served leaf while the listener stays up and keeps serving.
  • Local: cargo test -p dig-node-service (170 tests) green; cargo fmt --check + cargo clippy -D warnings clean.

Blast radius (gitnexus/manual)

Additive: new src/tls.rs, new serve_https/bring_up_local_https in server.rs (called once from serve_with_shutdown, best-effort spawned tasks — mirrors the existing mTLS listener pattern), two new Config accessors, one new const. No existing handler/route/bind semantics change; the plaintext path is untouched. SPEC §4.1a added.

⚠️ Do NOT merge yet — SECURITY-CRITICAL

Touches the ca.key rotation read pathdual gate (loop-reviewer + adversarial loop-decider) + loop-security required before merge.

Windows rollout note (non-blocking)

The Windows rollout gates on #623's DACL on the TLS root (installer provisions + locks down the CA). The build/tests here do not depend on it (fail-soft when no leaf).

SYSTEM.md / canonical coherence (for the orchestrator to commit — superproject-owned)

  • SYSTEM.md dig-node section + §5.3 ladder: add https://dig.local = 127.0.0.2:443 (+ [::1]:443), leaf from dig-cert, rotation owner = dig-node, no anchor auto-rotate.
  • canonical skill: dig.local HTTPS = 127.0.0.2:443.

🤖 Generated with Claude Code

…(#624)

Serve the SAME local content router over TLS on 127.0.0.2:443 (https://dig.local),
plus a best-effort [::1]:443 IPv6-loopback sibling (SS5.2), beside the kept plaintext
:80 listener. TLS material comes from the dig-cert crate (pinned git-dep tag v0.1.0,
release-first): the reloadable rustls ServerConfig is built via load_server_config.

Leaf rotation is delegated to dig-cert's RenewalManager (the node is the runtime
OWNER): a startup + daily maintain pass re-issues the leaf from ca.key at <30d
remaining, atomically swaps the pair, and fires resolver.reload() so the running
listener serves the new leaf with no downtime. The CA anchor is NEVER auto-rotated
here (only ca_renewal_due is reported; rotate_ca is installer-coordinated).

Fail-soft: when the installer (#623) has not provisioned a CA/leaf, or the leaf
cannot be loaded, HTTPS is skipped and the node serves plaintext only -- HTTPS is
never a hard requirement to start.

SECURITY-CRITICAL: touches the ca.key rotation read path -> dual gate + loop-security
required before merge. Windows rollout gates on #623's DACL (noted, non-blocking).

Tests: config addressing units; tls fail-soft + load units; an end-to-end HTTPS
integration test (client trusting the CA gets the content; a live rotation swaps the
served leaf with the listener staying up).

Bump 0.32.0 -> 0.33.0 (feat -> minor).

Closes #624
Refs #620, #622
Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d MichaelTaylor3d changed the title feat(serve): HTTPS on dig.local (127.0.0.2:443) + leaf rotation (#624) feat(serve): HTTPS on dig.local (127.0.0.2:443) + live leaf rotation (#624) Jul 16, 2026
@MichaelTaylor3d
MichaelTaylor3d marked this pull request as ready for review July 16, 2026 09:11
@MichaelTaylor3d
MichaelTaylor3d merged commit 54f41d1 into main Jul 16, 2026
17 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the feat/624-https-serve branch July 16, 2026 11:30
Sign up for free to 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