mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 06:42:12 +03:00
dast-smoke.yml and 3 nightly API-only smoke workflows (nightly-schemathesis, nightly-resilience, nightly-llm-security) ran "npm run build:cli" with no preceding full build or downloaded .build/next artifact. scripts/build/ prepublish.ts silently falls back to a full Next.js production build (dashboard UI + ~126 leaf pages + prerender) whenever the standalone server.js is missing, which is always the case in these jobs. That inline full build is the actual thing varying 6-29min on GitHub-hosted runners. These workflows only exercise API routes (schemathesis/promptfoo hit /api/monitoring/health, /v1/chat/completions, /v1/models, /api/auth, /api/keys) and never touch the dashboard UI, so set OMNIROUTE_BUILD_BACKEND_ONLY=1 on their "Build CLI bundle" step — an existing, previously-unused escape hatch (scripts/build/backendOnlyPages.mjs) that stubs the dashboard pages before the build and restores them after, leaving every route.ts API handler intact. npm-publish.yml is intentionally left untouched: it legitimately ships the full dashboard UI in the published npm package. Regression guard: tests/unit/build/backend-only-smoke-workflows.test.ts asserts OMNIROUTE_BUILD_BACKEND_ONLY=1/OMNIROUTE_BUILD_PROFILE=backend on all 5 "Build CLI bundle" steps across the 4 fixed workflows, and asserts npm-publish.yml's build step is NOT backend-only.
This commit is contained in:
committed by
GitHub
parent
0c6041a34e
commit
d1730f5b8a
2
.github/workflows/dast-smoke.yml
vendored
2
.github/workflows/dast-smoke.yml
vendored
@@ -27,6 +27,8 @@ jobs:
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
- name: Build CLI bundle
|
||||
env:
|
||||
OMNIROUTE_BUILD_BACKEND_ONLY: "1"
|
||||
run: npm run build:cli
|
||||
- name: Start OmniRoute
|
||||
env:
|
||||
|
||||
8
.github/workflows/nightly-llm-security.yml
vendored
8
.github/workflows/nightly-llm-security.yml
vendored
@@ -19,7 +19,9 @@ jobs:
|
||||
with: { node-version: "24", cache: npm }
|
||||
- run: npm ci
|
||||
- name: Build CLI bundle
|
||||
env: { JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation }
|
||||
env:
|
||||
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
|
||||
OMNIROUTE_BUILD_BACKEND_ONLY: "1"
|
||||
run: npm run build:cli
|
||||
- name: Start OmniRoute (block mode)
|
||||
env:
|
||||
@@ -72,7 +74,9 @@ jobs:
|
||||
if: steps.gate.outputs.run == 'true'
|
||||
- name: Build CLI bundle
|
||||
if: steps.gate.outputs.run == 'true'
|
||||
env: { JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation }
|
||||
env:
|
||||
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
|
||||
OMNIROUTE_BUILD_BACKEND_ONLY: "1"
|
||||
run: npm run build:cli
|
||||
- name: Start OmniRoute
|
||||
if: steps.gate.outputs.run == 'true'
|
||||
|
||||
1
.github/workflows/nightly-resilience.yml
vendored
1
.github/workflows/nightly-resilience.yml
vendored
@@ -51,6 +51,7 @@ jobs:
|
||||
- name: Build CLI bundle
|
||||
env:
|
||||
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
|
||||
OMNIROUTE_BUILD_BACKEND_ONLY: "1"
|
||||
run: npm run build:cli
|
||||
- name: Start OmniRoute (background)
|
||||
env:
|
||||
|
||||
4
.github/workflows/nightly-schemathesis.yml
vendored
4
.github/workflows/nightly-schemathesis.yml
vendored
@@ -20,7 +20,9 @@ jobs:
|
||||
with: { node-version: "24", cache: npm }
|
||||
- run: npm ci
|
||||
- name: Build CLI bundle
|
||||
env: { JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation }
|
||||
env:
|
||||
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
|
||||
OMNIROUTE_BUILD_BACKEND_ONLY: "1"
|
||||
run: npm run build:cli
|
||||
- name: Start OmniRoute (background)
|
||||
env:
|
||||
|
||||
1
changelog.d/fixes/7226-dast-smoke-backend-only.md
Normal file
1
changelog.d/fixes/7226-dast-smoke-backend-only.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(ci): build dast-smoke and nightly API-only smoke workflows with `OMNIROUTE_BUILD_BACKEND_ONLY=1` to skip the unused dashboard UI graph and stop the multi-minute build variance/timeouts (#7226)
|
||||
88
tests/unit/build/backend-only-smoke-workflows.test.ts
Normal file
88
tests/unit/build/backend-only-smoke-workflows.test.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
// Regression guard for #7226: API-only smoke/nightly workflows must build with
|
||||
// OMNIROUTE_BUILD_BACKEND_ONLY=1 so `npm run build:cli`'s fallback full build
|
||||
// (scripts/build/prepublish.ts -> build-next-isolated.mjs) skips the ~126-leaf-page
|
||||
// dashboard UI graph these workflows never exercise. Without this env var, the
|
||||
// "Build CLI bundle" step silently runs a full Next.js production build inline,
|
||||
// which is the actual source of the multi-minute variance/timeouts reported in #7226.
|
||||
//
|
||||
// npm-publish.yml is intentionally excluded: its "Build CLI bundle (standalone app)"
|
||||
// step legitimately ships the full dashboard UI in the published npm package.
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
interface WorkflowStep {
|
||||
name?: string;
|
||||
run?: string;
|
||||
env?: Record<string, string>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface WorkflowJob {
|
||||
steps: WorkflowStep[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface WorkflowDoc {
|
||||
jobs: Record<string, WorkflowJob>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const WORKFLOWS_DIR = path.join(process.cwd(), ".github", "workflows");
|
||||
|
||||
function loadWorkflow(fileName: string): WorkflowDoc {
|
||||
const raw = fs.readFileSync(path.join(WORKFLOWS_DIR, fileName), "utf8");
|
||||
return yaml.load(raw) as WorkflowDoc;
|
||||
}
|
||||
|
||||
function isBackendOnly(step: WorkflowStep): boolean {
|
||||
const env = step.env || {};
|
||||
return env.OMNIROUTE_BUILD_BACKEND_ONLY === "1" || env.OMNIROUTE_BUILD_PROFILE === "backend";
|
||||
}
|
||||
|
||||
// jobName: null selector means "any job" — used when a file has exactly one
|
||||
// "Build CLI bundle" step but we don't want to hardcode/duplicate the job key.
|
||||
interface Target {
|
||||
file: string;
|
||||
jobName: string;
|
||||
stepName: string;
|
||||
}
|
||||
|
||||
const TARGETS: Target[] = [
|
||||
{ file: "dast-smoke.yml", jobName: "dast-smoke", stepName: "Build CLI bundle" },
|
||||
{ file: "nightly-schemathesis.yml", jobName: "schemathesis", stepName: "Build CLI bundle" },
|
||||
{ file: "nightly-resilience.yml", jobName: "k6-soak", stepName: "Build CLI bundle" },
|
||||
{ file: "nightly-llm-security.yml", jobName: "promptfoo-guard", stepName: "Build CLI bundle" },
|
||||
{ file: "nightly-llm-security.yml", jobName: "garak", stepName: "Build CLI bundle" },
|
||||
];
|
||||
|
||||
for (const { file, jobName, stepName } of TARGETS) {
|
||||
test(`${file} :: ${jobName} '${stepName}' step sets OMNIROUTE_BUILD_BACKEND_ONLY=1 (skips dashboard UI build the API-only smoke job never exercises)`, () => {
|
||||
const doc = loadWorkflow(file);
|
||||
const job = doc.jobs[jobName];
|
||||
assert.ok(job, `${file} must have a '${jobName}' job`);
|
||||
const step = job.steps.find((s) => s.name === stepName);
|
||||
assert.ok(step, `${file}'s '${jobName}' job must have a '${stepName}' step`);
|
||||
assert.equal(
|
||||
isBackendOnly(step),
|
||||
true,
|
||||
`${file}'s '${jobName}' -> '${stepName}' step must set OMNIROUTE_BUILD_BACKEND_ONLY=1 or OMNIROUTE_BUILD_PROFILE=backend`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test("npm-publish.yml 'Build CLI bundle (standalone app)' step must NOT be backend-only (it legitimately ships the full dashboard UI)", () => {
|
||||
const doc = loadWorkflow("npm-publish.yml");
|
||||
const publishJob = Object.values(doc.jobs).find((job) =>
|
||||
job.steps.some((s) => s.name === "Build CLI bundle (standalone app)")
|
||||
);
|
||||
assert.ok(publishJob, "npm-publish.yml must have a job with a 'Build CLI bundle (standalone app)' step");
|
||||
const step = publishJob!.steps.find((s) => s.name === "Build CLI bundle (standalone app)")!;
|
||||
assert.equal(
|
||||
isBackendOnly(step),
|
||||
false,
|
||||
"npm-publish.yml's build step must ship the full dashboard UI, not the backend-only stub"
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user