Skip to content

Commit 2d6dc5e

Browse files
committed
ci: address review on OpenAPI contract checks (#37)
- Use fileURLToPath(import.meta.url) for REPO_ROOT in both scripts (portable on Windows and paths with spaces). - Guard that the parsed spec is a non-null object before accessing properties, so `null`/array JSON yields a clean validation error instead of a TypeError crash. Covered by a new regression test.
1 parent 32c70e2 commit 2d6dc5e

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

scripts/test-openapi-contract.mjs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import fs from "node:fs";
1010
import os from "node:os";
1111
import path from "node:path";
1212
import process from "node:process";
13+
import { fileURLToPath } from "node:url";
1314

14-
const REPO_ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
15+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
1516
const VALIDATOR = path.join(REPO_ROOT, "scripts/validate-openapi-contract.mjs");
1617
const REAL_SPEC = path.join(REPO_ROOT, "docs/openapi/qveris-public-api.openapi.json");
1718
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "qveris-openapi-contract-"));
@@ -46,6 +47,13 @@ const tests = [
4647
assert.equal(result.status, 1);
4748
assert.match(result.stderr, /not valid JSON/);
4849
}],
50+
["rejects valid JSON that is not an object", () => {
51+
const target = path.join(tmpRoot, "null.json");
52+
fs.writeFileSync(target, "null");
53+
const result = run(target);
54+
assert.equal(result.status, 1);
55+
assert.match(result.stderr, /not a valid OpenAPI object/);
56+
}],
4957
["rejects missing info.version", () => {
5058
const target = writeSpec("no-version.json", (spec) => {
5159
delete spec.info.version;

scripts/validate-openapi-contract.mjs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
import fs from "node:fs";
1313
import path from "node:path";
1414
import process from "node:process";
15+
import { fileURLToPath } from "node:url";
1516

16-
const REPO_ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
17+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
1718
const DEFAULT_SPEC = path.join("docs", "openapi", "qveris-public-api.openapi.json");
1819

1920
// Core agent-path endpoints the toolkit calls. Listed in the issue.
@@ -73,6 +74,11 @@ function main() {
7374
return;
7475
}
7576

77+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
78+
fail([`${rel} is not a valid OpenAPI object`]);
79+
return;
80+
}
81+
7682
if (typeof spec.openapi !== "string" || !spec.openapi) {
7783
errors.push("missing top-level `openapi` version string");
7884
}

0 commit comments

Comments
 (0)