test: harden package boundaries and audit budgets
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/captcha",
|
||||
"version": "0.8.13",
|
||||
"version": "0.8.14",
|
||||
"description": "First-class CAPTCHA challenges, providers, verification guards, page gates, and WRNexusJS UI.",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -47,4 +47,17 @@ describe("CAPTCHA helper boundaries", () => {
|
||||
).toEqual({ success: true, provider: "custom", action: "login" });
|
||||
expect(captchaContext({ locals: { captcha: "forged" } } as never)).toBeNull();
|
||||
});
|
||||
|
||||
test("does not convert provider transport failures into successful verification", async () => {
|
||||
const provider = {
|
||||
name: "custom" as const,
|
||||
client: { responseField: "captchaToken" },
|
||||
verify: async () => {
|
||||
throw new Error("provider timeout");
|
||||
},
|
||||
};
|
||||
await expect(
|
||||
verifyCaptchaOrThrow(provider, { providerToken: "x", action: "checkout" }),
|
||||
).rejects.toThrow("provider timeout");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-toolbar",
|
||||
"version": "0.8.15",
|
||||
"version": "0.8.16",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@@ -23,3 +23,19 @@ test("server issues have stable fingerprints and retain actionable error context
|
||||
expect(error.metadata?.stack).toContain("database offline");
|
||||
expect(error.recommendation).toContain("stack trace");
|
||||
});
|
||||
|
||||
test("non-Error throws are normalized without losing caller context", () => {
|
||||
const issue = issueFromError(
|
||||
{ reason: "offline" },
|
||||
{
|
||||
ruleId: "server/dependency",
|
||||
title: "Dependency failed",
|
||||
pathname: "/health",
|
||||
source: { file: "app/api/health.ts", line: 4 },
|
||||
},
|
||||
);
|
||||
expect(issue.ruleId).toBe("server/dependency");
|
||||
expect(issue.title).toBe("Dependency failed");
|
||||
expect(issue.message).toBe("[object Object]");
|
||||
expect(issue.fingerprint).toContain("app/api/health.ts:4:0");
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/store",
|
||||
"version": "0.8.11",
|
||||
"version": "0.8.12",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -30,3 +30,33 @@ test("memory persistence includes only approved fields and migrates old state",
|
||||
expect(second.state.theme).toBe("light-v2");
|
||||
expect(second.state.secret).toBe("initial");
|
||||
});
|
||||
|
||||
test("invalid persisted state fails closed to the store defaults", async () => {
|
||||
const name = `preferences-validation-${crypto.randomUUID()}`;
|
||||
const firstDefinition = defineStore({
|
||||
name,
|
||||
kind: "global" as const,
|
||||
createSharedState: () => ({ theme: "dark" }),
|
||||
persist: { storage: "memory" as const, version: 1, include: ["theme"] },
|
||||
actions: {
|
||||
setTheme: {
|
||||
runtime: "client" as const,
|
||||
handler: ({ state }: any, theme: string) => void (state.theme = theme),
|
||||
},
|
||||
},
|
||||
});
|
||||
const first = await new StoreContainer({ runtime: "client" }).use(firstDefinition);
|
||||
await first.actions.setTheme("corrupt");
|
||||
|
||||
const validated = defineStore({
|
||||
...firstDefinition,
|
||||
persist: {
|
||||
storage: "memory" as const,
|
||||
version: 1,
|
||||
include: ["theme"],
|
||||
validate: (value: any) => (value?.theme === "light" ? value : null),
|
||||
},
|
||||
});
|
||||
const second = await new StoreContainer({ runtime: "client" }).use(validated);
|
||||
expect(second.state.theme).toBe("dark");
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/syntax",
|
||||
"version": "0.8.15",
|
||||
"version": "0.8.16",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -26,3 +26,10 @@ test("api entries normalize methods and reject malformed request fields", () =>
|
||||
parseApiSections("request { body { missingType } } response { return data }"),
|
||||
).toThrow('Expected "name: type"');
|
||||
});
|
||||
|
||||
test("api entries reject truncated blocks and bare response bodies", () => {
|
||||
expect(() => parseApiEntries("lookup GET /users { response { return data }")).toThrow();
|
||||
expect(() => parseApiEntries("lookup GET /users { return data }")).toThrow(
|
||||
'declare a "response { }" section',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.8.12",
|
||||
"version": "0.8.13",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -43,4 +43,13 @@ describe("upload policy hardening", () => {
|
||||
).rejects.toThrow("store");
|
||||
expect(await verifySignedFileToken("not-a-token", "long-enough-secret")).toBeNull();
|
||||
});
|
||||
|
||||
test("signed file tokens reject expiry, tampering, and the wrong signing key", async () => {
|
||||
const value = { store: "uploads", key: "safe/report.pdf", expiresAt: 2_000 };
|
||||
const token = await createSignedFileToken(value, "long-enough-secret");
|
||||
expect(await verifySignedFileToken(token, "long-enough-secret", 1_999)).toEqual(value);
|
||||
expect(await verifySignedFileToken(token, "long-enough-secret", 2_000)).toBeNull();
|
||||
expect(await verifySignedFileToken(`${token}x`, "long-enough-secret", 1_999)).toBeNull();
|
||||
expect(await verifySignedFileToken(token, "different-long-secret", 1_999)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user