feat(phase-4): persistent architectural and network test harness

This commit is contained in:
Tyler Gillispie 2026-08-27 20:45:09 -07:00
parent 5bbe2bc764
commit c9390a881d
8 changed files with 290 additions and 0 deletions

View File

@ -17,6 +17,10 @@ export function streamDatastar(
aborted: boolean; aborted: boolean;
}) => Promise<void>, }) => Promise<void>,
) { ) {
// Set anti-buffering headers for Nginx / Traefik reverse proxies
c.header("X-Accel-Buffering", "no");
c.header("Cache-Control", "no-cache, no-transform");
return streamSSE(c, async (stream) => { return streamSSE(c, async (stream) => {
// Add custom datastar helper methods // Add custom datastar helper methods
const adapter = { const adapter = {

View File

@ -3,6 +3,7 @@ import { serveStatic } from "jsr:@hono/hono@4/deno";
import { initDb } from "./core/db.ts"; import { initDb } from "./core/db.ts";
import { pingValkey } from "./core/valkey.ts"; import { pingValkey } from "./core/valkey.ts";
import { contentNegotiation } from "./core/content_negotiation.ts"; import { contentNegotiation } from "./core/content_negotiation.ts";
import { payloadCapGuard } from "./core/auth_guards.ts";
import { authRoutes } from "./features/auth/routes.tsx"; import { authRoutes } from "./features/auth/routes.tsx";
import { adminRoutes } from "./features/admin/routes.tsx"; import { adminRoutes } from "./features/admin/routes.tsx";
@ -11,6 +12,7 @@ import { sessionRoutes } from "./features/sessions/routes.tsx";
const app: Hono = new Hono(); const app: Hono = new Hono();
app.use("*", payloadCapGuard);
app.use("*", contentNegotiation()); app.use("*", contentNegotiation());
// Serve static assets (specifically Datastar and client scripts) // Serve static assets (specifically Datastar and client scripts)

View File

@ -0,0 +1,43 @@
import { assertEquals } from "jsr:@std/assert@1";
import { determineClientType } from "../../core/content_negotiation.ts";
import { Hono } from "jsr:@hono/hono@4";
Deno.test("[Arch] Content Negotiation: Correctly resolves datastar, browser, shell, and cli clients", async () => {
const testApp = new Hono();
testApp.get("/test-negotiate", (c) => {
const clientType = determineClientType(c);
return c.json({ clientType });
});
// Test 1: Datastar request
const reqDatastar = new Request("http://localhost/test-negotiate", {
headers: { "Datastar-Request": "true" },
});
const resDatastar = await testApp.fetch(reqDatastar);
const dataDatastar = await resDatastar.json();
assertEquals(dataDatastar.clientType, "datastar");
// Test 2: Standard Browser HTML request
const reqBrowser = new Request("http://localhost/test-negotiate", {
headers: { "Accept": "text/html" },
});
const resBrowser = await testApp.fetch(reqBrowser);
const dataBrowser = await resBrowser.json();
assertEquals(dataBrowser.clientType, "browser");
// Test 3: Curl CLI request for shell script
const reqShell = new Request("http://localhost/test-negotiate", {
headers: { "User-Agent": "curl/7.88.1" },
});
const resShell = await testApp.fetch(reqShell);
const dataShell = await resShell.json();
assertEquals(dataShell.clientType, "shell");
// Test 4: Explicit JSON REST client
const reqJson = new Request("http://localhost/test-negotiate", {
headers: { "Accept": "application/json" },
});
const resJson = await testApp.fetch(reqJson);
const dataJson = await resJson.json();
assertEquals(dataJson.clientType, "cli");
});

View File

@ -0,0 +1,28 @@
import { assertEquals, assertStringIncludes } from "jsr:@std/assert@1";
import { renderErrorToastFragment } from "../../core/error_fragments.tsx";
import app from "../../main.ts";
Deno.test("[Arch] Error Fragment: renderErrorToastFragment outputs Datastar morph target #status-banner", async () => {
const errorMessage = "Invalid PIN code or workshop pass expired.";
const fragment = renderErrorToastFragment(errorMessage);
const html = String(await fragment);
assertStringIncludes(html, 'id="status-banner"');
assertStringIncludes(html, errorMessage);
assertStringIncludes(html, "display: block;");
});
Deno.test("[Arch] Error Fragment: Validation errors on action routes return HTML fragments", async () => {
const req = new Request("http://localhost/api/join", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const res = await app.fetch(req);
assertEquals(res.status, 400);
const html = await res.text();
assertStringIncludes(html, 'id="status-banner"');
assertStringIncludes(html, "Event code or PIN is required");
});

View File

@ -0,0 +1,29 @@
import { assertEquals } from "jsr:@std/assert@1";
import { Hono } from "jsr:@hono/hono@4";
import { streamDatastar } from "../../core/sse_adapter.ts";
Deno.test("[Arch] Proxy Buffering: streamDatastar emits anti-buffering headers", async () => {
const testApp = new Hono();
testApp.get("/api/test-sse", (c) => {
return streamDatastar(c, async (stream) => {
await stream.write({
event: "datastar-fragment",
data: '<span id="status">Active</span>',
});
});
});
const res = await testApp.fetch(new Request("http://localhost/api/test-sse"));
assertEquals(res.status, 200);
// Assert required proxy headers to bypass Nginx / Traefik buffer accumulation
assertEquals(res.headers.get("x-accel-buffering"), "no");
assertEquals(
res.headers.get("content-type")?.includes("text/event-stream"),
true,
);
assertEquals(
res.headers.get("cache-control")?.includes("no-cache"),
true,
);
});

View File

@ -0,0 +1,54 @@
import { assertEquals } from "jsr:@std/assert@1";
import { Hono } from "jsr:@hono/hono@4";
import { streamDatastar } from "../../core/sse_adapter.ts";
Deno.test("[Arch] SSE Lifecycle: streamDatastar executes clean teardown on client abort", async () => {
let setupExecuted = false;
let teardownExecuted = false;
const testApp = new Hono();
testApp.get("/test/stream", (c) => {
return streamDatastar(c, async (stream) => {
setupExecuted = true;
try {
await stream.write({
event: "datastar-fragment",
data: "<div>Connected</div>",
});
// Simulate keepalive loop until abort
while (!stream.aborted) {
await stream.sleep(10);
}
} finally {
teardownExecuted = true;
}
});
});
const abortController = new AbortController();
const req = new Request("http://localhost/test/stream", {
signal: abortController.signal,
});
const res = await testApp.fetch(req);
assertEquals(res.status, 200);
assertEquals(res.headers.get("content-type"), "text/event-stream");
// Read first chunk to ensure stream has started
const reader = res.body?.getReader();
if (reader) {
const { value } = await reader.read();
const text = new TextDecoder().decode(value);
assertEquals(text.includes("<div>Connected</div>"), true);
assertEquals(setupExecuted, true);
// Abort connection
abortController.abort();
await reader.cancel();
}
// Allow microtasks to complete teardown
await new Promise((resolve) => setTimeout(resolve, 50));
assertEquals(teardownExecuted, true);
});

View File

@ -0,0 +1,54 @@
import { assertEquals, assertNotEquals } from "jsr:@std/assert@1";
import app from "../../main.ts";
Deno.test("[Arch] Transport Efficiency: Point-to-point routes return text/html or application/json without SSE overhead", async () => {
// Test 1: Public Join Page
const startJoin = performance.now();
const resJoin = await app.fetch(new Request("http://localhost/join"));
const durationJoin = performance.now() - startJoin;
assertEquals(resJoin.status, 200);
assertEquals(
resJoin.headers.get("content-type")?.includes("text/html"),
true,
);
assertNotEquals(
resJoin.headers.get("content-type"),
"text/event-stream",
);
// Ensure synchronous rendering execution is rapid (<50ms under test runtime)
assertEquals(durationJoin < 100, true);
// Test 2: Login Route
const startLogin = performance.now();
const resLogin = await app.fetch(new Request("http://localhost/login"));
const durationLogin = performance.now() - startLogin;
assertEquals(resLogin.status, 200);
assertEquals(
resLogin.headers.get("content-type")?.includes("text/html"),
true,
);
assertNotEquals(
resLogin.headers.get("content-type"),
"text/event-stream",
);
assertEquals(durationLogin < 100, true);
});
Deno.test("[Arch] Transport Efficiency: Invariant payload cap guard prevents oversized requests (>16KB)", async () => {
// Create an oversized body (20KB)
const largeBody = "A".repeat(20 * 1024);
const req = new Request("http://localhost/api/join", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": String(largeBody.length),
},
body: JSON.stringify({ code: largeBody }),
});
const res = await app.fetch(req);
// Max 16KB payload cap guard triggers 413 Payload Too Large or 400 validation
assertEquals(res.status === 413 || res.status === 400, true);
});

View File

@ -0,0 +1,76 @@
import { assertNotEquals, assertStringIncludes } from "jsr:@std/assert@1";
import { EventCockpitDeckFragment } from "../../features/events/fragments.tsx";
import { SessionTableFragment } from "../../features/sessions/fragments.tsx";
import { AdminUsersPageFragment } from "../../features/admin/fragments.tsx";
Deno.test("[Arch] XSS Fuzzing: EventCockpitDeckFragment escapes malicious event names and payloads", () => {
const xssPayload =
'<script>alert("xss")</script><img src=x onerror=alert(1)>';
const mockEvents = [
{
id: "event-1",
name: xssPayload,
slug: "xss-test",
pin_code: "123-456",
seats_claimed: 5,
max_seats: 50,
expires_at: new Date().toISOString(),
},
];
const html = String(<EventCockpitDeckFragment eventPasses={mockEvents} />);
// Assert raw script tag is NOT rendered
assertNotEquals(html.includes('<script>alert("xss")</script>'), true);
// Assert escaped HTML entity is present
assertStringIncludes(html, "&lt;script&gt;");
});
Deno.test("[Arch] XSS Fuzzing: SessionTableFragment escapes malicious session labels", () => {
const xssLabel = '"><script>alert(document.cookie)</script>';
const mockSessions = [
{
id: "sess-xss",
label: xssLabel,
is_agent: true,
custom_scopes: ["read:events"],
created_at: new Date().toISOString(),
expires_at: new Date().toISOString(),
},
];
const html = String(
<SessionTableFragment
sessions={mockSessions}
currentSessionId="sess-xyz"
/>,
);
assertNotEquals(
html.includes('"><script>alert(document.cookie)</script>'),
true,
);
assertStringIncludes(html, "&lt;script&gt;");
});
Deno.test("[Arch] XSS Fuzzing: AdminUsersPageFragment escapes malicious usernames and emails", () => {
const xssUsername = '<img src=x onerror=fetch("evil.com")>';
const mockUsers = [
{
id: "user-1",
username: xssUsername,
role: "viewer",
created_at: new Date().toISOString(),
},
];
const html = String(
<AdminUsersPageFragment users={mockUsers} />,
);
assertNotEquals(
html.includes('<img src=x onerror=fetch("evil.com")>'),
true,
);
assertStringIncludes(html, "&lt;img");
});