Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/production-audit-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"auditLevel": "high",
"scope": "Production dependencies declared by each published package, resolved in isolated consumer manifests without monorepo overrides",
"acceptedAdvisories": [
{
"id": "GHSA-xcpc-8h2w-3j85",
"package": "adm-zip",
"severity": "high",
"affectedArtifacts": [
"@cortexkit/opencode-magic-context",
"@cortexkit/pi-magic-context"
],
"dependencyPath": "@huggingface/transformers@4.2.0 > onnxruntime-node@1.24.3 > adm-zip@0.5.18",
"reachability": "onnxruntime-node uses adm-zip only during native-provider installation; runtime inference does not parse ZIP input",
"owner": "cortexkit/magic-context maintainers",
"rationale": "No released onnxruntime-node version permits patched adm-zip@0.6.x; acceptance is temporary pending the upstream range change and coordinated Transformers release",
"expires": "2026-11-17",
"upstream": [
"https://github.com/huggingface/transformers.js/issues/1727",
"https://github.com/microsoft/onnxruntime/pull/29772",
"https://github.com/huggingface/transformers.js/pull/1731"
]
},
{
"id": "GHSA-f88m-g3jw-g9cj",
"package": "sharp",
"severity": "high",
"affectedArtifacts": [
"@cortexkit/opencode-magic-context",
"@cortexkit/pi-magic-context"
],
"dependencyPath": "@huggingface/transformers@4.2.0 > sharp@0.34.5",
"reachability": "Magic Context uses the Transformers text-embedding pipeline and does not pass image input to sharp",
"owner": "cortexkit/magic-context maintainers",
"rationale": "Transformers' released ^0.34.5 range cannot select patched sharp@0.35.x; acceptance is temporary pending the upstream range change and release",
"expires": "2026-11-17",
"upstream": [
"https://github.com/huggingface/transformers.js/issues/1729",
"https://github.com/huggingface/transformers.js/pull/1731"
]
}
]
}
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ env:
# every PR and master push exercises the full unit → Docker → host gauntlet.

jobs:
audit-production:
name: Audit (published production dependencies)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.10"

- name: Test production audit policy
run: bun run test:audit-production

- name: Reject unaccepted HIGH production advisories
run: bun run audit:production

check-plugin:
name: Check (plugin)
runs-on: ubuntu-latest
Expand Down
24 changes: 20 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ env:

# Pipeline shape (each stage gates the next via `needs:`):
#
# test, test-pi, test-cli (unit tests, parallel)
# audit-production, test, test-pi, test-cli (policy/audit + unit tests, parallel)
# ↓
# e2e-opencode, e2e-pi (Docker install + smoke, parallel — gated by unit tests)
# ↓
Expand Down Expand Up @@ -47,6 +47,22 @@ env:
# (workflow_dispatch only) for re-announcements and external releases.

jobs:
audit-production:
name: Audit (published production dependencies)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.10"

- name: Test production audit policy
run: bun run test:audit-production

- name: Reject unaccepted HIGH production advisories
run: bun run audit:production

test:
name: Test (plugin)
runs-on: ubuntu-latest
Expand Down Expand Up @@ -329,7 +345,7 @@ jobs:
# Publishes are gated on the full e2e suite (OpenCode + Pi) so a tag
# push can never produce a published npm package whose runtime fails
# the install + first-turn smoke test.
needs: [test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
needs: [audit-production, test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
steps:
- uses: actions/checkout@v5

Expand Down Expand Up @@ -368,7 +384,7 @@ jobs:
publish-npm-pi:
name: Publish pi-plugin to npm
runs-on: ubuntu-latest
needs: [test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
needs: [audit-production, test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
steps:
- uses: actions/checkout@v5

Expand Down Expand Up @@ -402,7 +418,7 @@ jobs:
publish-npm-cli:
name: Publish unified CLI to npm
runs-on: ubuntu-latest
needs: [test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
needs: [audit-production, test, test-pi, test-cli, e2e-opencode, e2e-pi, e2e-host-opencode, e2e-host-pi]
steps:
- uses: actions/checkout@v5

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"test:rust": "cargo test --workspace",
"lint:rust": "cargo fmt --check && cargo clippy --workspace --all-targets -- -D warnings",
"fmt:rust": "cargo fmt",
"audit:production": "bash scripts/audit-production.sh",
"test:audit-production": "bun test scripts/audit-production.test.ts",
"check:all": "bun run test && cargo test --workspace && cargo clippy --workspace --all-targets -- -D warnings",
"build:dists": "bun run --cwd packages/plugin build && bun run --cwd packages/pi-plugin build"
}
Expand Down
3 changes: 3 additions & 0 deletions packages/plugin/src/tui/tui-compiled-runtime-imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ describe("compiled TUI runtime imports", () => {
* Built from the shared list so the test cannot cover fewer modules than the
* build rewrites. */
async function loadExportSets(): Promise<Record<string, Set<string>>> {
// @opentui/core/testing subclasses a core export during module initialization;
// warm core before the parallel imports so Bun cannot expose its TDZ.
await import("@opentui/core");
const entries = await Promise.all(
TUI_RUNTIME_SPECIFIERS.map(
async (specifier) =>
Expand Down
205 changes: 205 additions & 0 deletions scripts/audit-production-input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
export type AcceptedAdvisory = {
readonly id: string;
readonly package: string;
readonly severity: "high" | "critical";
readonly affectedArtifacts: readonly string[];
readonly dependencyPath: string;
readonly reachability: string;
readonly owner: string;
readonly rationale: string;
readonly expires: string;
readonly upstream: readonly string[];
};

export type AuditPolicy = {
readonly auditLevel: "high";
readonly scope: string;
readonly acceptedAdvisories: readonly AcceptedAdvisory[];
};

export type ProductionManifest = {
readonly name: string;
readonly version: string;
readonly private: true;
readonly [key: string]: unknown;
};

export class AuditInputError extends Error {}

export function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}

export function requiredString(value: unknown, field: string): string {
if (
typeof value !== "string" ||
value.trim() !== value ||
value.length === 0
) {
throw new AuditInputError(`${field} must be a non-empty trimmed string`);
}
return value;
}

function stringArray(value: unknown, field: string): readonly string[] {
if (!Array.isArray(value) || value.length === 0) {
throw new AuditInputError(`${field} must be a non-empty string array`);
}
return value.map((item, index) => requiredString(item, `${field}[${index}]`));
}

export function isPackageName(value: string): boolean {
return /^(?:@[a-z0-9._~-]+\/)?[a-z0-9._~-]+$/i.test(value);
}

function parseResolvedNode(value: string, field: string): string {
const separator = value.lastIndexOf("@");
const packageName = value.slice(0, separator);
const version = value.slice(separator + 1);
if (
separator < 1 ||
!isPackageName(packageName) ||
!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)
) {
throw new AuditInputError(`${field} must contain exact package@version nodes`);
}
return packageName;
}

function isoDate(value: unknown, field: string): string {
const date = requiredString(value, field);
const parsed = new Date(`${date}T00:00:00.000Z`);
if (
!/^\d{4}-\d{2}-\d{2}$/.test(date) ||
Number.isNaN(parsed.valueOf()) ||
parsed.toISOString().slice(0, 10) !== date
) {
throw new AuditInputError(`${field} must be a real YYYY-MM-DD date`);
}
return date;
}

export function httpsUrl(value: string, field: string): string {
let parsed: URL;
try {
parsed = new URL(value);
} catch (error) {
if (error instanceof TypeError)
throw new AuditInputError(`${field} must be a valid HTTPS URL`);
throw error;
}
if (
parsed.protocol !== "https:" ||
parsed.username !== "" ||
parsed.password !== "" ||
parsed.hostname === ""
) {
throw new AuditInputError(`${field} must be a credential-free HTTPS URL`);
}
return value;
}

function parseAcceptedAdvisory(
value: unknown,
index: number,
today: string,
): AcceptedAdvisory {
if (!isRecord(value))
throw new AuditInputError(`acceptedAdvisories[${index}] must be an object`);
const field = (name: string): string => `acceptedAdvisories[${index}].${name}`;
const id = requiredString(value.id, field("id"));
if (
!/^(?:GHSA-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}|CVE-\d{4}-\d{4,})$/i.test(id)
) {
throw new AuditInputError(`${field("id")} must be a GHSA or CVE ID`);
}
const packageName = requiredString(value.package, field("package"));
if (!isPackageName(packageName))
throw new AuditInputError(`${field("package")} is invalid`);
if (value.severity !== "high" && value.severity !== "critical") {
throw new AuditInputError(`${field("severity")} must be high or critical`);
}
const affectedArtifacts = stringArray(value.affectedArtifacts, field("affectedArtifacts"));
if (affectedArtifacts.some((artifact) => !isPackageName(artifact))) {
throw new AuditInputError(
`${field("affectedArtifacts")} contains an invalid package name`,
);
}
const dependencyPath = requiredString(value.dependencyPath, field("dependencyPath"));
const pathPackages = dependencyPath
.split(" > ")
.map((node, nodeIndex) =>
parseResolvedNode(node, `${field("dependencyPath")}[${nodeIndex}]`),
);
if (pathPackages.at(-1) !== packageName) {
throw new AuditInputError(
`${field("dependencyPath")} must end with ${packageName}@version`,
);
}
const expires = isoDate(value.expires, field("expires"));
if (expires <= today) throw new AuditInputError(`${id} acceptance expired on ${expires}`);
const upstream = stringArray(value.upstream, field("upstream")).map((url, urlIndex) =>
httpsUrl(url, `${field("upstream")}[${urlIndex}]`),
);
return {
id,
package: packageName,
severity: value.severity,
affectedArtifacts,
dependencyPath,
reachability: requiredString(value.reachability, field("reachability")),
owner: requiredString(value.owner, field("owner")),
rationale: requiredString(value.rationale, field("rationale")),
expires,
upstream,
};
}

export function parsePolicy(value: unknown, today: string): AuditPolicy {
if (!isRecord(value))
throw new AuditInputError("production audit policy must be an object");
if (value.auditLevel !== "high")
throw new AuditInputError("production audit policy auditLevel must be high");
if (!Array.isArray(value.acceptedAdvisories)) {
throw new AuditInputError(
"production audit policy acceptedAdvisories must be an array",
);
}
isoDate(today, "current date");
return {
auditLevel: "high",
scope: requiredString(value.scope, "production audit policy scope"),
acceptedAdvisories: value.acceptedAdvisories.map((entry, index) =>
parseAcceptedAdvisory(entry, index, today),
),
};
}

function dependencyGroup(
value: unknown,
field: string,
): Readonly<Record<string, unknown>> | undefined {
if (value === undefined) return undefined;
if (!isRecord(value)) throw new AuditInputError(`${field} must be an object`);
return value;
}

export function createProductionManifest(value: unknown): ProductionManifest {
if (!isRecord(value))
throw new AuditInputError("package manifest must be an object");
const manifest: Record<string, unknown> & ProductionManifest = {
name: requiredString(value.name, "package name"),
version: requiredString(value.version, "package version"),
private: true,
};
for (const group of [
"dependencies",
"optionalDependencies",
"peerDependencies",
"peerDependenciesMeta",
] as const) {
const dependencies = dependencyGroup(value[group], group);
if (dependencies !== undefined) manifest[group] = dependencies;
}
return manifest;
}
Loading
Loading