3f3f6e81
docs+test: Task 11 follow-through — the test's name tells the truth, the buffer admits its guess
a73x 2026-08-12 19:56
Commit message
src/main.zig
| Old | New | ||
|---|---|---|---|
| @@ -756,6 +756,12 @@ fn announceKeyFrom(env: ?[]const u8, dflt: ?[]const u8) KeyResult { | |||
| 756 | /// was asked. That is now a fact rather than a convention: the words are | 756 | /// was asked. That is now a fact rather than a convention: the words are |
| 757 | /// `quic.keyRefusalBody`'s, and this half owns only the prefix and the | 757 | /// `quic.keyRefusalBody`'s, and this half owns only the prefix and the |
| 758 | /// `; staying on ssh` that says what the refusal cost. | 758 | /// `; staying on ssh` that says what the refusal cost. |
| 759 | /// | ||
| 760 | /// Every error is handed over, catch-all included: `announceKeyFrom` only | ||
| 761 | /// reaches `load_failed` with what the load returned, so an unclassified | ||
| 762 | /// error here is still a key that would not read — which is what the | ||
| 763 | /// body's fourth sentence says. `run`'s arm above routes only the three | ||
| 764 | /// for the opposite reason: it can afford to let the rest propagate. | ||
| 759 | fn reportKeyRefusal(path: []const u8, err: anyerror) void { | 765 | fn reportKeyRefusal(path: []const u8, err: anyerror) void { |
| 760 | var buf: [quic.key_refusal_len]u8 = undefined; | 766 | var buf: [quic.key_refusal_len]u8 = undefined; |
| 761 | std.debug.print( | 767 | std.debug.print( |
| @@ -1189,7 +1195,7 @@ test "askEndpointPort: a socket nobody serves answers 0, quickly" { | |||
| 1189 | try std.testing.expect(std.time.milliTimestamp() - t0 < 500); | 1195 | try std.testing.expect(std.time.milliTimestamp() - t0 < 500); |
| 1190 | } | 1196 | } |
| 1191 | 1197 | ||
| 1192 | test "oneShotQuery: a socket nobody serves is exit 1, and the verb is in the line" { | 1198 | test "oneShotQuery: a socket nobody serves is exit 1" { |
| 1193 | const testtmp = @import("testtmp"); | 1199 | const testtmp = @import("testtmp"); |
| 1194 | var tmp = try testtmp.TmpDir.make(); | 1200 | var tmp = try testtmp.TmpDir.make(); |
| 1195 | defer tmp.cleanup(); | 1201 | defer tmp.cleanup(); |
| @@ -1200,6 +1206,11 @@ test "oneShotQuery: a socket nobody serves is exit 1, and the verb is in the lin | |||
| 1200 | // both are right: `stop` asked for a state the absence already satisfies, | 1206 | // both are right: `stop` asked for a state the absence already satisfies, |
| 1201 | // while `dump` and `stats` asked a question nothing answered. Sharing one | 1207 | // while `dump` and `stats` asked a question nothing answered. Sharing one |
| 1202 | // round-trip between the two query verbs must not quietly make it three. | 1208 | // round-trip between the two query verbs must not quietly make it three. |
| 1209 | // | ||
| 1210 | // The exit is all this pins. Both verbs are run because both must reach | ||
| 1211 | // that verdict, but the line naming the verb goes to stderr rather than | ||
| 1212 | // being returned, so nothing here can assert it — the way `lostMsg` and | ||
| 1213 | // `keyRefusalBody` are asserted is by being pure, and this is not. | ||
| 1203 | try std.testing.expectEqual( | 1214 | try std.testing.expectEqual( |
| 1204 | @as(u8, 1), | 1215 | @as(u8, 1), |
| 1205 | try oneShotQuery(std.testing.allocator, sock, "dump", .debug_dump, "", .dump_reply), | 1216 | try oneShotQuery(std.testing.allocator, sock, "dump", .debug_dump, "", .dump_reply), |
src/quic.zig
| Old | New | ||
|---|---|---|---|
| @@ -122,9 +122,17 @@ pub const Key = struct { | |||
| 122 | } | 122 | } |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
| 125 | /// A buffer big enough for any refusal body: the longest sentence, a path | 125 | /// A buffer for one refusal body: PATH_MAX for the path, and 128 for |
| 126 | /// at PATH_MAX, and an error name. Past this the body clips — see the | 126 | /// everything else in the line. |
| 127 | /// truncation note on `keyRefusalBody`. | 127 | /// |
| 128 | /// The 128 is chosen, not derived, and the honest reason is the catch-all. | ||
| 129 | /// The longest fixed text is 53 bytes (` is not a key: want 32 raw bytes | ||
| 130 | /// or 64 hex characters`), which would size itself — but the catch-all | ||
| 131 | /// also appends an `@errorName`, and the only bound on that is the longest | ||
| 132 | /// error name in the binary, a number no source line here can name. So | ||
| 133 | /// this is `open_err_len`'s kind of number, picked to put truncation out | ||
| 134 | /// of reach, and it is `keyRefusalBody`'s clipping that makes choosing | ||
| 135 | /// rather than deriving safe. | ||
| 128 | pub const key_refusal_len = std.fs.max_path_bytes + 128; | 136 | pub const key_refusal_len = std.fs.max_path_bytes + 128; |
| 129 | 137 | ||
| 130 | /// The middle sentence of every key refusal, in every binary — one owner | 138 | /// The middle sentence of every key refusal, in every binary — one owner |
src/server.zig
| Old | New | ||
|---|---|---|---|
| @@ -831,6 +831,12 @@ pub const Server = struct { | |||
| 831 | // and this site owns only the prefix. An operator who has seen one | 831 | // and this site owns only the prefix. An operator who has seen one |
| 832 | // message should not have to learn a second phrasing for it, and | 832 | // message should not have to learn a second phrasing for it, and |
| 833 | // this site's catch-all used to be exactly that second phrasing. | 833 | // this site's catch-all used to be exactly that second phrasing. |
| 834 | // | ||
| 835 | // Every error is routed, catch-all included, because every error | ||
| 836 | // here can only have come from the load: there is nothing else in | ||
| 837 | // this expression to have failed. So an unclassified one is still a | ||
| 838 | // key that would not read, which is exactly what the body's fourth | ||
| 839 | // sentence says. | ||
| 834 | const key = quic.Key.load(key_path) catch |err| { | 840 | const key = quic.Key.load(key_path) catch |err| { |
| 835 | var buf: [quic.key_refusal_len]u8 = undefined; | 841 | var buf: [quic.key_refusal_len]u8 = undefined; |
| 836 | std.debug.print( | 842 | std.debug.print( |