Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
21b82d7
Share semantic audit admission across managed scans
mldangelo-oai Sep 12, 2026
4ee012f
test: prepare audit draft before finalization
mldangelo-oai Sep 12, 2026
b2512b3
Preserve helper CLI behavior through linked plugin paths
mldangelo-oai Sep 12, 2026
67d586d
fix: resolve SDK dependencies in native policy proof
mldangelo-oai Sep 12, 2026
6bcec28
Classify accepted audit drafts once
mldangelo-oai Sep 16, 2026
9ea1b22
Merge updated shared execution into audit admission
mldangelo-oai Sep 16, 2026
8741d3f
Merge shared execution formatting
mldangelo-oai Sep 16, 2026
9593aad
Format shared audit imports and types
mldangelo-oai Sep 16, 2026
92b3d5c
Merge shared execution tests into audit admission
mldangelo-oai Sep 16, 2026
5f8a618
Preserve canonical admission with selected older plugins
mldangelo-oai Sep 16, 2026
c2b4101
Merge resolved worker settings compatibility
mldangelo-oai Sep 16, 2026
494afbf
Merge per-session worker selection isolation
mldangelo-oai Sep 16, 2026
72cd751
Merge standalone MCP dependency resolution
mldangelo-oai Sep 16, 2026
82cf99c
Use canonical field rules for persisted audit admission
mldangelo-oai Sep 16, 2026
b71cb8b
Include the shared contract path helper in package checks
mldangelo-oai Sep 16, 2026
f77d9bf
Keep unsealed question inputs compatible with finalization
mldangelo-oai Sep 16, 2026
36fee2f
Check question normalization without requiring deduplication
mldangelo-oai Sep 16, 2026
d53829a
Preserve pre-finalization coverage metadata inputs
mldangelo-oai Sep 16, 2026
cd74e91
Merge selected provider projection into admission control
mldangelo-oai Sep 16, 2026
97ee643
Merge package Python discovery correction into admission control
mldangelo-oai Sep 16, 2026
361340b
Compose package interpreter identity assertion correction
mldangelo-oai Sep 16, 2026
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
65 changes: 39 additions & 26 deletions plugins/codex-security/mcp-app/helpers-main.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
import { existsSync, realpathSync } from "node:fs";
import { fileURLToPath } from "node:url";
export { parseCanonicalScanDraft } from "./src/artifact-scan-draft.js";
import { resolveSecurityMdCommand } from "./src/helpers/resolve-security-md";
import { decodePosixBytes } from "./src/helpers/posix-path";
import { windowsBinding } from "./src/native";

let commandLine = process.argv.slice(2);
if (process.platform === "win32") {
const original = windowsBinding().windowsArguments();
commandLine = original
.slice(original.length - commandLine.length)
.map((argument) => argument.toString("utf16le"));
}
let posixHome = process.env.HOME;
if (commandLine[0] === "--helper") {
// Importing the bundled helper from the SDK does not invoke its CLI adapter.
const entryPath = import.meta.url.startsWith("file:") ? fileURLToPath(import.meta.url) : import.meta.url;
const invokedPath = process.argv[1];
if (
invokedPath && existsSync(invokedPath)
&& realpathSync(invokedPath) === realpathSync(entryPath)
) runHelper();

function runHelper(): void {
let commandLine = process.argv.slice(2);
if (process.platform === "win32") {
commandLine = commandLine.slice(1);
const original = windowsBinding().windowsArguments();
commandLine = original
.slice(original.length - commandLine.length)
.map((argument) => argument.toString("utf16le"));
}
let posixHome = process.env.HOME;
if (commandLine[0] === "--helper") {
if (process.platform === "win32") {
commandLine = commandLine.slice(1);
} else {
const [homeSet, home, ...args] = decodePosixBytes(
Buffer.from(commandLine[1] ?? "", "hex"),
)
.split("\0")
.slice(0, -1);
posixHome = homeSet ? home : undefined;
commandLine = args;
}
}
const [command, ...args] = commandLine;
if (command === "resolve-security-md") {
process.exitCode = resolveSecurityMdCommand(args, posixHome);
} else {
const [homeSet, home, ...args] = decodePosixBytes(
Buffer.from(commandLine[1] ?? "", "hex"),
)
.split("\0")
.slice(0, -1);
posixHome = homeSet ? home : undefined;
commandLine = args;
console.error(
"Usage: launch_codex_security_mcp[.cmd] --helper resolve-security-md [options]",
);
process.exitCode = 2;
}
}
const [command, ...args] = commandLine;
if (command === "resolve-security-md") {
process.exitCode = resolveSecurityMdCommand(args, posixHome);
} else {
console.error(
"Usage: launch_codex_security_mcp[.cmd] --helper resolve-security-md [options]",
);
process.exitCode = 2;
}
1 change: 1 addition & 0 deletions plugins/codex-security/mcp-app/scripts/build_mcp_app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,6 @@ const runtimeModule = new Module(loaderPath);
runtimeModule.filename = loaderPath;
runtimeModule.paths = Module._nodeModulePaths(dirname(loaderPath));
runtimeModule._compile(runtimeSource, loaderPath);
export default runtimeModule.exports;
`;
}
155 changes: 110 additions & 45 deletions plugins/codex-security/mcp-app/src/artifact-scan-draft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { dirname, join, sep } from "node:path";
import type * as z from "zod/v4";
import commonSchema from "../../schemas/definitions/artifact-common.schema.json";
import scanDraftDocument from "../../schemas/tools/scan-draft.schema.json";
import scanManifestDocument from "../../schemas/scan-manifest.schema.json";
import coverageDocument from "../../schemas/coverage.schema.json";
import findingsDocument from "../../schemas/findings.schema.json";
import { safeRelativePath } from "../../../../sdk/typescript/src/contract-path.js";
import type { ArtifactContext } from "./artifact-context.js";
import type { RunArtifactWorkbench } from "./artifact-context.js";
import {
Expand All @@ -17,17 +21,10 @@ import {
type SchemaDocument,
} from "./artifact-schema-loader.js";

type JsonObject = Record<string, unknown>;
import type { ScanDraftInput } from "../../../../sdk/typescript/src/accepted-audit.js";
export type { ScanDraftInput } from "../../../../sdk/typescript/src/accepted-audit.js";

export interface ScanDraftInput {
scanId: string;
complete?: boolean;
handoffClaimToken?: string;
scope?: JsonObject;
threatModel?: JsonObject;
findings: JsonObject[];
coverage: JsonObject;
}
type JsonObject = Record<string, unknown>;

export interface CompletedScanInput {
scanId: string;
Expand Down Expand Up @@ -69,6 +66,58 @@ export const scanDraftInputSchema = loadArtifactZodSchema(
"scanDraftInput",
) as z.ZodType<ScanDraftInput>;

// Keep draft completion/host-field handling, using canonical persisted field rules.
const canonicalScanDraftInputSchema = loadArtifactZodSchema(
[commonSchema, {
...scanDraftDocument,
$defs: {
...scanDraftDocument.$defs,
scanId: scanManifestDocument.properties.scan.properties.id,
scope: {
...scanDraftDocument.$defs.scope,
properties: scanManifestDocument.properties.scan.properties.scope.properties,
},
threatModel: scanManifestDocument.properties.scan.properties.threatModel,
finding: {
...scanDraftDocument.$defs.finding,
properties: findingsDocument.properties.findings.items.properties,
},
coverage: {
...scanDraftDocument.$defs.coverage,
properties: {
...coverageDocument.properties,
surfaces: {
...coverageDocument.properties.surfaces,
items: {
...coverageDocument.properties.surfaces.items,
required: scanDraftDocument.$defs.surface.required,
},
},
deferred: {
...coverageDocument.properties.deferred,
items: {
...coverageDocument.properties.deferred.items,
required: scanDraftDocument.$defs.coverage.properties.deferred.items.required,
},
},
// String questions are normalized by the finalizer after admission.
openQuestions: {
...coverageDocument.properties.openQuestions,
items: {
anyOf: [
scanDraftDocument.$defs.coverage.properties.openQuestions.items.anyOf[0],
coverageDocument.properties.openQuestions.items,
],
},
},
},
},
},
}] as SchemaDocument[],
scanDraftDocument.$id,
"scanDraftInput",
) as z.ZodType<ScanDraftInput>;

export const completedScanInputSchema = loadArtifactZodSchema(
schemaDocuments,
scanDraftDocument.$id,
Expand Down Expand Up @@ -548,32 +597,9 @@ async function readPreviousScanDraft(
const manifest = parseJsonObject(contents[0]!, "previous scan draft manifest");
const findings = parseJsonObject(contents[1]!, "previous scan draft findings");
const coverage = parseJsonObject(contents[2]!, "previous scan draft coverage");
const scan = requireObject(manifest.scan, "previous scan draft.scan");
const semanticScope = isObject(scan.scope) ? { ...scan.scope } : undefined;
if (semanticScope) {
delete semanticScope.includePaths;
delete semanticScope.excludePaths;
}
const semanticCoverage = { ...coverage };
for (const field of ["documentType", "schemaVersion", "scanId", "mode", "includePaths", "excludePaths", "receiptRefs", "inventoryStrategy"]) delete semanticCoverage[field];
return {
digest,
input: parsePersistedScanDraft({
scanId: context.scanId,
...(scan.complete === false ? { complete: false } : {}),
...(semanticScope && Object.keys(semanticScope).length > 0
? { scope: semanticScope }
: {}),
...(isObject(scan.threatModel)
? { threatModel: structuredClone(scan.threatModel) }
: {}),
findings: (findings.findings as JsonObject[]).map((finding) => {
const semantic = { ...finding };
for (const field of ["findingId", "occurrenceId", "fingerprints"]) delete semantic[field];
return semantic;
}),
coverage: semanticCoverage,
}),
input: parseCanonicalScanDraft({ scanId: context.scanId, manifest, findings, coverage }),
};
}

Expand Down Expand Up @@ -973,8 +999,43 @@ export async function getCodexSecurityCompletedScan(
return { scanId: parsed.scanId, manifest, findings, coverage };
}

/** Admit canonical fields while retaining shared audit semantics and path safety. */
export function parseCanonicalScanDraft(input: {
scanId?: string;
manifest: JsonObject;
findings: JsonObject;
coverage: JsonObject;
}): ScanDraftInput {
const scan = requireObject(input.manifest.scan, "scan draft manifest.scan");
for (const scanId of [scan.id, input.findings.scanId, input.coverage.scanId]) {
if (scanId !== undefined && scanId !== input.scanId) {
throw new Error("scan draft: canonical documents belong to a different scan.");
}
}
const parsed = parsePersistedCheckpoint({
scanId: input.scanId,
...(scan.complete === undefined ? {} : { complete: scan.complete }),
...(scan.scope === undefined ? {} : { scope: scan.scope }),
...(scan.threatModel === undefined ? {} : { threatModel: scan.threatModel }),
findings: input.findings.findings,
coverage: input.coverage,
}, canonicalScanDraftInputSchema);
for (const [index, finding] of parsed.findings.entries()) {
for (const field of ["locations", "codeEvidence"] as const) {
for (const [locationIndex, location] of ((finding[field] as JsonObject[] | undefined) ?? []).entries()) {
safeRelativePath(location.path as string, `findings[${index}].${field}[${locationIndex}].path`);
}
}
}
return parsed;
}

export function parseScanDraft(input: ScanDraftInput): ScanDraftInput {
const parsed = scanDraftInputSchema.parse(input);
return parseSemanticScanDraft(input, scanDraftInputSchema);
}

function parseSemanticScanDraft(input: unknown, schema: z.ZodType<ScanDraftInput>): ScanDraftInput {
const parsed = schema.parse(input);
validateFindingSemantics(parsed.findings);
validateCoverageSemantics(parsed.coverage);
return parsed;
Expand All @@ -984,18 +1045,22 @@ export function parseScanDraft(input: ScanDraftInput): ScanDraftInput {
export function parsePersistedScanDraft(
input: Record<string, unknown>
): ScanDraftInput {
const compatible = structuredClone(input);
if (!Array.isArray(compatible.findings)) {
return parseScanDraft(compatible as unknown as ScanDraftInput);
}
for (const finding of compatible.findings) {
if (!isObject(finding)) continue;
normalizePersistedFindingDetails(finding);
return parsePersistedDraft(structuredClone(input), scanDraftInputSchema);
}

function parsePersistedDraft(compatible: Record<string, unknown>, schema: z.ZodType<ScanDraftInput>): ScanDraftInput {
if (Array.isArray(compatible.findings)) {
for (const finding of compatible.findings) {
if (isObject(finding)) normalizePersistedFindingDetails(finding);
}
}
return parseScanDraft(compatible as unknown as ScanDraftInput);
return parseSemanticScanDraft(compatible, schema);
}

function parsePersistedCheckpoint(input: Record<string, unknown>): ScanDraftInput {
function parsePersistedCheckpoint(
input: Record<string, unknown>,
schema = scanDraftInputSchema,
): ScanDraftInput {
const compatible = structuredClone(input);
if (isObject(compatible.scope)) {
delete compatible.scope.includePaths;
Expand All @@ -1022,7 +1087,7 @@ function parsePersistedCheckpoint(input: Record<string, unknown>): ScanDraftInpu
delete finding.fingerprints;
}
}
return parsePersistedScanDraft(compatible);
return parsePersistedDraft(compatible, schema);
}

function normalizePersistedFindingDetails(finding: JsonObject): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ export async function validateDiscoveryArtifacts(
artifacts: DeepScanArtifacts,
resultPath: string,
expectedScanId: string
): Promise<ScanDraftInput> {
const result = await readDiscoveryAuditDraft(artifacts, resultPath, expectedScanId);
if (result.complete === false) throw new Error("Standard scan worker wrote only a checkpoint; its audit is not complete.");
return result;
}

export async function readDiscoveryAuditDraft(
artifacts: DeepScanArtifacts,
resultPath: string,
expectedScanId: string,
): Promise<ScanDraftInput> {
await requireRegularFile(resultPath, artifacts.workersRoot);
const result = parseStoredScanDraft(
Expand All @@ -58,7 +68,6 @@ export async function validateDiscoveryArtifacts(
expectedScanId,
parsePersistedScanDraft
);
if (result.complete === false) throw new Error("Standard scan worker wrote only a checkpoint; its audit is not complete.");
return result;
}

Expand Down
Loading
Loading