release: v1.32.0 — hardening and scalability (#580)

* release: prepare v1.32.0

* test: stabilize water capture re-entry
This commit is contained in:
Marc-André Bombeck authored and GitHub committed 2026-07-22 04:14:15 +02:00
1 parent b01822be48
commit 62eb431d66
372 files changed
+25178 -8561

No files matched your search

+38
View File
@@ -7,6 +7,8 @@
* exit-code behaviour is best left to a smoke test in CI (deferred to
* v1.4.43).
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { checkEnv, parseEnvFile } from "../check-env";
@@ -252,3 +254,39 @@ describe("checkEnv — optional groups (informational)", () => {
expect(apnsKeyId.required).toBe(false);
});
});
describe("environment inventory", () => {
it("lists every optional AI runtime variable in compose, both examples, and the manifest", () => {
const repositoryRoot = join(__dirname, "../..");
const variableNames = [
"ALLOW_LOCAL_AI_PRIVATE_HOSTS",
"INSIGHTS_MAX_TOKENS",
];
const compose = readFileSync(
join(repositoryRoot, "docker-compose.yml"),
"utf8",
);
const exampleEnvironments = [
readFileSync(join(repositoryRoot, ".env.example"), "utf8"),
readFileSync(join(repositoryRoot, ".env.production.example"), "utf8"),
];
const manifest = JSON.parse(
readFileSync(join(repositoryRoot, "scripts/env-manifest.json"), "utf8"),
) as {
groups: Array<{ variables: Array<{ name: string }> }>;
};
const manifestNames = manifest.groups.flatMap((group) =>
group.variables.map((variable) => variable.name),
);
for (const variableName of variableNames) {
expect(compose).toMatch(new RegExp(`^\\s*${variableName}:`, "m"));
for (const exampleEnvironment of exampleEnvironments) {
expect(exampleEnvironment).toMatch(
new RegExp(`^# ${variableName}=`, "m"),
);
}
expect(manifestNames).toContain(variableName);
}
});
});
+8
View File
@@ -45,6 +45,14 @@ describe("Playwright CI determinism", () => {
expect(config.retries).toBe(2);
expect(config.failOnFlakyTests).toBe(true);
expect(config.reporter).toEqual([["github"], ["html", { open: "never" }]]);
expect(config.webServer).toMatchObject({
command: expect.stringContaining(
`${JSON.stringify(process.execPath)} .next/standalone/server.js`,
),
env: expect.objectContaining({
NATIVE_CANVAS: "off",
}),
});
});
it("retains the Playwright report after every workflow outcome", () => {
+15
View File
@@ -117,6 +117,21 @@
}
]
},
{
"name": "AI Provider",
"description": "Optional runtime policy and output tuning for user-configured AI providers. Each variable stands alone and has a safe default when unset.",
"required": false,
"variables": [
{
"name": "ALLOW_LOCAL_AI_PRIVATE_HOSTS",
"purpose": "Local-AI SSRF opt-in. Unset rejects private/internal hosts; set an exact comma-separated host allowlist or \"true\" to allow any private host."
},
{
"name": "INSIGHTS_MAX_TOKENS",
"purpose": "Daily-briefing output-token ceiling. Default 2500, clamped to 500-8000."
}
]
},
{
"name": "APNs (iOS push)",
"description": "All four core APNS_* vars together. Missing any disables APNs silently — the v1.4.40 AP-2 gap that motivated this manifest. allOrNone trips the synthetic <all-or-none> required row whenever 1-3 of the 4 are set.",