Skip to content
Merged
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
21 changes: 15 additions & 6 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,13 @@ jobs:
- name: Set up TypeScript tools
uses: ./.github/actions/setup-tools
with:
cache-dependency-path: plugins/codex-security/mcp-app/pnpm-lock.yaml
cache-dependency-path: |
sdk/typescript/pnpm-lock.yaml
plugins/codex-security/mcp-app/pnpm-lock.yaml
- name: Install dependencies
run: pnpm --dir plugins/codex-security/mcp-app install --frozen-lockfile
run: |
pnpm --dir sdk/typescript install --frozen-lockfile
pnpm --dir plugins/codex-security/mcp-app install --frozen-lockfile
- name: Install ripgrep
run: |
sudo apt-get update
Expand Down Expand Up @@ -403,19 +407,24 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout plugin source without the SDK
- name: Checkout plugin and shared SDK source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
sparse-checkout: |
plugins/codex-security
sdk/typescript
.github/actions/setup-tools
- name: Set up TypeScript tools
uses: ./.github/actions/setup-tools
with:
cache-dependency-path: plugins/codex-security/mcp-app/pnpm-lock.yaml
- name: Install plugin dependencies
run: pnpm --dir plugins/codex-security/mcp-app install --frozen-lockfile
cache-dependency-path: |
plugins/codex-security/mcp-app/pnpm-lock.yaml
sdk/typescript/pnpm-lock.yaml
- name: Install plugin build dependencies
run: |
pnpm --dir sdk/typescript install --frozen-lockfile
pnpm --dir plugins/codex-security/mcp-app install --frozen-lockfile
- name: Build and test the standalone host runtime
run: node --test plugins/codex-security/mcp-app/scripts/test_host_build.mjs

Expand Down
3 changes: 3 additions & 0 deletions evals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ being embedded in its source tree or shipped npm runtime.
core audit finds synthetic credentials in source and keeps them in its final
findings, with deterministic grading and harness checks.

- [Completed-report merge](../sdk/typescript/scripts/merge-eval/README.md):
synthetic grouping quality checks and negative controls.

Model runs are opt-in. CI runs the deterministic triage and secret-discovery
helper checks and the real-IPC reducer regression through the normal MCP test
suite.
39 changes: 39 additions & 0 deletions plugins/codex-security/mcp-app/src/artifact-candidate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { z } from "zod";
import definitions from "../../schemas/definitions/discovery-candidate.schema.json";
import type {
RawDiscoveryCandidate,
RawDiscoveryLocation,
} from "./artifact-discovery.js";
import { loadArtifactZodSchema } from "./artifact-schema-loader.js";

type CandidateShape = {
[K in keyof RawDiscoveryCandidate]-?: K extends "locations"
? z.ZodArray<z.ZodType<Required<RawDiscoveryLocation>>>
: z.ZodType<RawDiscoveryCandidate[K]>;
} & { candidate_id: z.ZodString };

const candidate = loadArtifactZodSchema(
[definitions],
definitions.$id,
"discoveryCandidate",
) as z.ZodObject<CandidateShape>;

/** Exact discovery rows emitted by the shared candidate normalizer. */
export const candidateSchemaV1 = candidate
.strict()
.extend({
candidate_id: candidate.shape.candidate_id
.min(1)
.regex(/\S/u, "Must contain non-whitespace text"),
locations: candidate.shape.locations.element
.refine((location) => location.end_line >= location.start_line, {
message: "end_line must be greater than or equal to start_line",
path: ["end_line"],
})
.array()
.min(1),
})
.meta({
id: "codex-security-standard-scan-candidate-v1",
title: "Codex Security discovery candidate v1",
});
2 changes: 1 addition & 1 deletion plugins/codex-security/mcp-app/src/artifact-discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
loadArtifactZodSchema,
type SchemaDocument,
} from "./artifact-schema-loader.js";
import { candidateSchemaV1 } from "./deep-scan/artifact-contracts.js";
import { candidateSchemaV1 } from "./artifact-candidate.js";

const execFileAsync = promisify(execFile);
const discoveryComponents = ["artifacts", "02_discovery"] as const;
Expand Down
15 changes: 11 additions & 4 deletions plugins/codex-security/mcp-app/src/artifact-io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ export async function readArtifactTextWithMetadata(
} finally {
await handle.close();
}
} catch {
throw new Error(label + ": the requested artifact cannot be read.");
} catch (cause) {
throw new Error(label + ": the requested artifact cannot be read.", {
cause,
});
}
}

Expand All @@ -109,8 +111,13 @@ async function artifactSourcePath(
}
}

const canonical = await fs.realpath(current).catch(() => undefined);
if (!canonical || !canonical.startsWith(root + sep)) {
const canonical = await fs.realpath(current).catch((cause: unknown) => {
throw new Error(
label + ": the requested artifact escaped its bound context.",
{ cause },
);
});
if (!canonical.startsWith(root + sep)) {
throw new Error(
label + ": the requested artifact escaped its bound context.",
);
Expand Down
Loading
Loading