- C-2: new_acme dedups the acme-tls/1 ALPN append (idempotent construction); ACME/non-ACME ALPN asymmetry documented on TlsServerConfig::new; pinned by new_acme_caller_supplied_acme_tls_alpn_is_not_duplicated - C-3: new_acme rejects an empty domains list with TlsError::AcmeConfig before spawning the order loop; contact stays unvalidated (RFC 8555 7.3 zero-contact accounts are legal); pinned by new_acme_empty_domains_returns_config_error (acme-gated) - N-6: Cargo.toml exclude gains tasks/ and docs/architecture/ - N-7: AcmeDirectory::Custom documents the https-only caller contract (no runtime validation, per finding) Verification: cargo test (default) and --all-features (77 lib tests, 2 new), clippy -D warnings, fmt --check, doc, package --list (no tasks/ or docs/architecture/), publish --dry-run — all green
6.5 KiB
6.5 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| config-validation-and-trivia | Config robustness + trivia batch — ALPN dedup, empty-domains validation, packaging excludes, https doc line (C-2, C-3, N-6, N-7) | completed | narrow | low | component | implementation |
|
Description
Four small findings in one pass (all verified in the decomposition session):
- C-2 —
acme-tls/1is appended unconditionally (src/server.rs:91); a caller who already includes it inalpnsgets it twice (probed:alpn_protocols == [acme-tls/1, acme-tls/1]). Harmless to rustls-acme's challenge dispatch today, but the duplication leaks into the wire config and the ACME/non-ACME asymmetry is undocumented. Fix: a one-lineif !alpn.contains(&b"acme-tls/1".to_vec())guard — or pin the current shape in a doc note + test. The guard is the better default (idempotent construction), but either way a test pins the chosen shape. - C-3 —
TlsIdentity::Acmewith an emptydomainslist constructs successfully (probed) and spawns the order loop that then fails per-order at runtime as logged-only events. A one-line validation (if domains.is_empty() { return Err(TlsError::AcmeConfig("empty domain list".into())) }) at construction is additive and cheap. Note: emptycontactstays legal (RFC 8555 §7.3 allows zero-contact accounts) — do NOT validate that. Mechanics note (2026-09-12 re-check): the new test must be#[cfg(feature = "acme")]-gated like the existing ACME tests — under default features the Acme arm already errors withAcmeConfigfor the missing-feature reason (pinned bynew_acme_identity_without_feature_returns_config_error, server.rs), so a non-gated empty-domains test would pass vacuously and prove nothing. - N-6 —
tasks/*.mdanddocs/architecture/**ship in the published package (cargo package --listre-verified). One-lineexcludeaddition:"tasks/,"docs/architecture/per the alktunnels house pattern (internal SDD notes + architecture docs don't belong in the public package). - N-7 —
AcmeDirectory::Custom(String)accepts any string and the URL goes to rustls-acme verbatim, so anhttp://custom directory silently runs ACME over plaintext (token-bearing). One doc line on the variant ("must be anhttps://ACME directory URL") closes it. Do not add runtime URL validation — the doc line is the fix (a caller pointing at a non-https test directory should not be blocked).
Work
- C-2: the dedup guard (preferred) + a test pinning
idempotence (caller-supplied
acme-tls/1→ single entry). - C-3: the empty-domains validation + a test
(
TlsServerConfig::new(&Acme{domains: vec![]}, ..)→TlsError::AcmeConfig), feature-gated like the existing ACME tests. - N-6:
exclude = [... , "tasks/", "docs/architecture/"]; re-runcargo package --list --allow-dirty+cargo publish --dry-run --allow-dirty. - N-7: the doc line on
AcmeDirectory::Custom.
Verification
- Dedup: caller-supplied
acme-tls/1yields exactly one entry (test pinned) - Empty-domains ACME construction errors with
TlsError::AcmeConfig(test pinned) cargo package --list --allow-dirtycontains neithertasks/nordocs/architecture/;cargo publish --dry-run --allow-dirtypasses- The
Customvariant's doc states the https requirement cargo test,--all-features, clippy, fmt, doc green
Acceptance Criteria
- All four findings resolved (or explicitly doc-pinned with a test, per finding)
- No behavior change beyond the three intended ones
References
- docs/reviews/001-implementation-review.md §C-2, §C-3, §N-6, §N-7
- src/server.rs:91 (the ALPN append), src/server.rs:64-145
(
new_acme— where the domains validation goes), src/identity.rs:65 (AcmeDirectory::Custom), Cargo.toml:11 (exclude list) - (line refs re-checked 2026-09-12 against the post-ADR-007/008 tree; the file has shifted since the decomposition — re-grep before editing rather than trusting these absolutely)
Notes
- C-2: implemented the dedup guard (preferred option) in
new_acme—if !alpn.contains(&b"acme-tls/1".to_vec())before the push. Also documented the ACME/non-ACME ALPN asymmetry onTlsServerConfig::new(ACME always servesacme-tls/1, appended idempotently; non-ACME uses the caller's list verbatim). Pinned bynew_acme_caller_supplied_acme_tls_alpn_is_not_duplicated(src/server.rs,#[cfg(feature = "acme")]). - C-3: added the empty-domains validation at the top of
new_acme(before anyAcmeConfigconstruction or task spawn) returningTlsError::AcmeConfig("TlsIdentity::Acme requires a non-empty domain list").contactleft unvalidated per the finding (RFC 8555 §7.3 zero-contact accounts are legal). Testnew_acme_empty_domains_returns_config_erroris#[cfg(feature = "acme")]-gated per the task's mechanics note. - N-6:
excludenow also lists"tasks/"and"docs/architecture/". Verifiedcargo package --list --allow-dirtycontains neither path andcargo publish --dry-run --allow-dirtypasses. - N-7: doc line added on
AcmeDirectory::Custom(src/identity.rs): the URL goes to rustls-acme verbatim and must behttps://(anhttp://URL would run ACME token-bearing over plaintext); explicitly notes no runtime validation is applied so non-https test directories stay usable. No runtime check added, per the finding.
Summary
All four findings resolved. Changes:
src/server.rs—new_acmededups theacme-tls/1ALPN append (idempotent construction) and rejects an emptydomainslist withTlsError::AcmeConfigbefore spawning the order loop; the ACME/non-ACME ALPN asymmetry is documented onTlsServerConfig::new.src/identity.rs—AcmeDirectory::Customdocuments the https-only caller contract (no runtime validation, per finding).Cargo.toml—excludegains"tasks/"and"docs/architecture/".
New tests (both #[cfg(feature = "acme")]): caller-supplied
acme-tls/1 yields exactly one entry; empty domains constructs to
TlsError::AcmeConfig.
Verification: cargo test (default) and cargo test --all-features
(77 lib tests, both new tests pass), cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps,
cargo package --list --allow-dirty (no tasks/ / docs/architecture/
entries), cargo publish --dry-run --allow-dirty — all green.