milestone 17: real deadlines, validator holes, upstream editor, trusted proxies, contract samples, badvers
This commit is contained in:
+44
-2
@@ -78,6 +78,17 @@ total budget. Decision: the total budget becomes real.
|
||||
file's ceiling-only idiom: `1..1_000_000` with the "must be at most"
|
||||
message shape. No full memory-fit guarantee — out of reach, not needed.
|
||||
|
||||
**Recorded (implementation):** three consequences this ruling did not call
|
||||
out. (a) `cache.size = 0` was a documented "disables caching" mode; the
|
||||
`1..` floor removes it — configuration.md now says there is no off value
|
||||
(use 1). (b) The configuration.md NextDNS-DoT redaction passage lost its
|
||||
premise (a hostname `tls://` URL is now unconfigurable) and was rewritten.
|
||||
(c) Three config fixtures used `tls://dot.example:853` and now use an IP
|
||||
literal with `tls_name`; the back-up-and-restore.md export transcript grew
|
||||
to `head -10` with real re-captured output. Also: `Pool.init` takes a named
|
||||
`pool.Timeouts { attempt, total }` struct, not two positional durations —
|
||||
two same-typed adjacent parameters would be silently swappable.
|
||||
|
||||
### 3. The upstream editor is built
|
||||
|
||||
Milestone 8 ruling 9 requires upstream CRUD in the UI ("the Settings page
|
||||
@@ -179,6 +190,16 @@ address's 3-stream SSE cap. No X-Forwarded-For handling exists anywhere
|
||||
chain → 400); an integration test proving a proxied remote address is
|
||||
rate-limited while the proxy itself stays exempt.
|
||||
|
||||
**Recorded (implementation of ruling 4):** `Request.client_addr` is
|
||||
`std.Io.net.IpAddress`, not `address.NetAddress` — `http_util.zig` is a
|
||||
module root for the fuzz target and cannot import nxdns modules; any future
|
||||
ruling that wants a domain type on `Request` hits this. `clientAddr` reads
|
||||
only the final chain entry, never scanning backwards: an earlier entry is
|
||||
client-controlled, so a fallback would hand the request an attacker-chosen
|
||||
identity. Known residual, out of this ruling's list: the login log line in
|
||||
`handlers/auth.zig` still prints the socket peer, which reads as loopback
|
||||
behind a trusted proxy — carried to milestone 19.
|
||||
|
||||
### 5. A field-level contract guard between server and frontend
|
||||
|
||||
The REST contract lives in three hand-synced copies. The Zig side is
|
||||
@@ -217,6 +238,16 @@ Mechanism — captured samples validated by `tsc`, no new dependencies:
|
||||
checking, so a server field missing from types.ts, a types.ts field
|
||||
missing from the wire, and an out-of-union literal all fail
|
||||
`npm run typecheck` — which already runs in CI's frontend job.
|
||||
**Recorded (implementation):** canonicalization gained two rules beyond
|
||||
"keys sorted, numbers→0": repeated array elements dedupe by canonical text
|
||||
(60 identical zeroed timeseries buckets collapse to one; differing rows all
|
||||
stay), and two build-identity strings (`Version.git_commit`,
|
||||
`Version.zig_version`) redact to `"<build>"` so the golden is not pinned to
|
||||
one machine — the list is the named constant `volatile_string_keys`. The
|
||||
renderer emits prettier's own fixpoint output, because CI runs
|
||||
`format:check` on the tree. 43 samples: 38 endpoint + 5 error classes. The
|
||||
regen command is documented in AGENTS.md.
|
||||
|
||||
- Embedding: an anonymous-import root must be Zig, not TypeScript, so a
|
||||
wrapper `web/src/lib/contract_samples.zig` exports
|
||||
`pub const bytes = @embedFile("contractSamples.gen.ts");` and build.zig
|
||||
@@ -262,6 +293,13 @@ finding.
|
||||
`edns.extendedRcode`) and version 0 in the reply OPT; a version-0
|
||||
query is unaffected.
|
||||
|
||||
**Recorded (implementation):** the write-side splitter is
|
||||
`edns.splitRcode` with `pub const badvers: u12 = 16`; the BADVERS reply
|
||||
echoes the question when `qdcount == 1`, following the neighboring
|
||||
FORMERR sites, so a client can bind the reply to its query; a malformed
|
||||
OPT whose version byte is 1 answers FORMERR, because `parseOpt` fails
|
||||
before the version check can read the byte.
|
||||
|
||||
### 7. The stale phase comments state the as-built contract
|
||||
|
||||
- `rate_limiter.zig:5-6` ("Phase 7 decides the locking"): rewrite to the
|
||||
@@ -404,8 +442,12 @@ Deleted surface: the seven unused `get*` wrappers, `getMetrics`,
|
||||
types.ts type fails `npm run typecheck` (proven, then reverted).
|
||||
- [ ] A version-1 EDNS query answers composite RCODE 16 with version 0;
|
||||
`nxdns_dns_badvers_total` appears in /metrics.
|
||||
- [ ] Grep: "Phase 7" and "Phase 8" appear in no source doc comment;
|
||||
the rewritten headers state the mutex and the maintenance task.
|
||||
- [ ] "Phase 7"/"Phase 8" no longer appear in `rate_limiter.zig`,
|
||||
`shutdown.zig`, or `pool.zig`; the rewritten headers state the
|
||||
mutex and the maintenance task. (Narrowed during implementation:
|
||||
the original repo-wide grep exceeded ruling 7's three files — 24
|
||||
stale phase references remain in files this milestone's sessions
|
||||
do not own; the sweep moved to milestone 19.)
|
||||
- [ ] Grep: `0.1.0-dev` appears in no docs/ page; the new drift test
|
||||
passes and was proven able to fail (reinsert the literal, watch it
|
||||
fail, revert).
|
||||
|
||||
Reference in New Issue
Block a user