§8 review convergence (todo §8); re-ran the architecture + product reviewers to convergence — 5 rounds, until both returned zero new actionable findings. Fixed across rounds 1-4 (tests-first): bounded every outbound Ory fetch with a timeout (src/fetch-timeout.ts withTimeout + ORY_TIMEOUT_SEC default 5, incl. the http JWKS fetch) so a hung Ory can't park a request handler; anonymous on a permission-gated plugin route now 303→/login (was a dead-end 403; signed-in-without-role still 403); an already-signed-in user is sent home from /login + /registration; the onRequest hook short-circuit now sets the fresh CSRF cookie; admin-users malformed :id → 404 (was 500) via safeDecode; parseJwks validates key element shape (fails loud at load); removed the dead COOKIE_SECRET (loaded + enforced + documented but never read); documented HYDRA_ADMIN_URL; admin recovery shows the code + links to the public /recovery instead of the browser-unreachable admin-API link; reference-plugin breadcrumb-label + pagination/datetime README notes; corrected the contract doc to not over-promise a post-login "retry". Declined: unconditional base-ctx chrome (would build the menu per request, regressing the lazy hot path). Deferred → §9: return_to-preservation for deep-link login. Stability-reviewer on the cumulative diff: APPROVE, no Critical/High (addressed its Low nits). typecheck + 310 units + the full scripts/ci.sh gate (visual 9 · auth 1 · oauth 2 · full 6) green.
This commit is contained in:
+11
-9
@@ -5,7 +5,6 @@ import { loadConfig } from "./config.ts";
|
||||
// Explicit secure-secret enforcement (no environment sniffing): secrets are the only
|
||||
// thing a hardened deploy must supply.
|
||||
const secureEnv = {
|
||||
COOKIE_SECRET: "real-cookie-secret",
|
||||
CSRF_SECRET: "real-csrf-secret",
|
||||
REQUIRE_SECURE_SECRETS: "true",
|
||||
};
|
||||
@@ -20,7 +19,6 @@ test("loads dev defaults when the environment is empty", () => {
|
||||
assert.equal(c.ketoReadUrl, "http://keto:4466");
|
||||
assert.equal(c.ketoWriteUrl, "http://keto:4467");
|
||||
assert.equal(c.hydraAdminUrl, "http://hydra:4445");
|
||||
assert.match(c.cookieSecret, /dev-insecure/);
|
||||
assert.match(c.csrfSecret, /dev-insecure/);
|
||||
assert.equal(c.jwtClockSkewSec, 60); // default exp/nbf leeway for Kratos↔web clock drift
|
||||
});
|
||||
@@ -51,10 +49,10 @@ test("parses explicit boolean toggles and rejects non-boolean values", () => {
|
||||
});
|
||||
|
||||
test("reads overrides from the environment", () => {
|
||||
const c = loadConfig({ COOKIE_SECRET: "x", KRATOS_PUBLIC_URL: "https://id.example.com", PORT: "8080" });
|
||||
const c = loadConfig({ CSRF_SECRET: "x", KRATOS_PUBLIC_URL: "https://id.example.com", PORT: "8080" });
|
||||
assert.equal(c.port, 8080);
|
||||
assert.equal(c.kratosPublicUrl, "https://id.example.com");
|
||||
assert.equal(c.cookieSecret, "x");
|
||||
assert.equal(c.csrfSecret, "x");
|
||||
});
|
||||
|
||||
test("rejects an invalid PORT", () => {
|
||||
@@ -67,22 +65,26 @@ test("JWT_CLOCK_SKEW_SEC: parses a non-negative integer, rejects junk (E2E short
|
||||
for (const v of ["-1", "1.5", "abc"]) assert.throws(() => loadConfig({ JWT_CLOCK_SKEW_SEC: v }), /JWT_CLOCK_SKEW_SEC/);
|
||||
});
|
||||
|
||||
test("ORY_TIMEOUT_SEC: defaults to 5 and must be a positive integer (0 would abort every Ory call)", () => {
|
||||
assert.equal(loadConfig({}).oryTimeoutSec, 5);
|
||||
assert.equal(loadConfig({ ORY_TIMEOUT_SEC: "10" }).oryTimeoutSec, 10);
|
||||
for (const v of ["0", "-1", "1.5", "abc"]) assert.throws(() => loadConfig({ ORY_TIMEOUT_SEC: v }), /ORY_TIMEOUT_SEC/);
|
||||
});
|
||||
|
||||
test("rejects a malformed Ory URL", () => {
|
||||
assert.throws(() => loadConfig({ KETO_READ_URL: "not a url" }), /KETO_READ_URL/);
|
||||
});
|
||||
|
||||
test("REQUIRE_SECURE_SECRETS rejects a missing or dev-throwaway secret", () => {
|
||||
assert.throws(() => loadConfig({ REQUIRE_SECURE_SECRETS: "true" }), /COOKIE_SECRET/);
|
||||
assert.throws(() => loadConfig({ COOKIE_SECRET: "real", REQUIRE_SECURE_SECRETS: "true" }), /CSRF_SECRET/);
|
||||
assert.throws(() => loadConfig({ REQUIRE_SECURE_SECRETS: "true" }), /CSRF_SECRET/);
|
||||
assert.throws(
|
||||
() => loadConfig({ COOKIE_SECRET: "dev-insecure-cookie-secret", CSRF_SECRET: "real", REQUIRE_SECURE_SECRETS: "true" }),
|
||||
/COOKIE_SECRET/,
|
||||
() => loadConfig({ CSRF_SECRET: "dev-insecure-csrf-secret", REQUIRE_SECURE_SECRETS: "true" }),
|
||||
/CSRF_SECRET/,
|
||||
);
|
||||
});
|
||||
|
||||
test("REQUIRE_SECURE_SECRETS succeeds with real secrets and still defaults the Ory URLs", () => {
|
||||
const c = loadConfig(secureEnv);
|
||||
assert.equal(c.cookieSecret, "real-cookie-secret");
|
||||
assert.equal(c.csrfSecret, "real-csrf-secret");
|
||||
assert.equal(c.kratosPublicUrl, "http://kratos:4433"); // only secrets are enforced; URLs still default
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user