mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-16 18:05:31 +02:00
* feat(cso): add verified audits and replayable repair bundles * fix(cso): harden qualification and setup boundaries * fix(cso): assemble security canaries at runtime * fix(cso): bound release proof and maintenance work Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): require complete evaluation reports Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): replay expired snapshots from supplied source Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): synchronize DNS cancellation assertion Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore(ship): exempt repository owner from liveness proof Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): make recheck retention overlap deterministic Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: bump version and changelog (v1.85.0.0) Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass native release gates Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.86.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): resolve rechecks by finding Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.87.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass macOS and Windows release gates Normalize BSD wc output, compare Windows paths by filesystem identity, preserve portable snapshot race coverage, and narrow POSIX-only Windows fixtures. Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): harden native verification gates * fix(cso): refine Windows native diagnostics * test(cso): isolate Windows Git startup failure * test(cso): stabilize Windows native diagnostics * fix(cso): support hardened Git on Windows * fix(cso): close final verification gaps * test(cso): bound cold Docker fixture setup * fix(cso): restore cross-platform free-suite gates --------- Co-authored-by: OpenAI Codex <noreply@openai.com>
149 lines
4.5 KiB
TypeScript
149 lines
4.5 KiB
TypeScript
import { createHash } from 'node:crypto';
|
|
|
|
export type ProducerHost = 'claude' | 'codex' | 'gemini';
|
|
export type ProducerVersion = 'v2' | 'v3';
|
|
export type ProducerMode = 'daily' | 'comprehensive';
|
|
export type ProducerStack = 'node' | 'bun' | 'python' | 'rails';
|
|
export type ProducerVariant = 'vulnerable' | 'fixed';
|
|
|
|
export interface ProducerCell {
|
|
id: string;
|
|
caseId: string;
|
|
stack: ProducerStack;
|
|
variant: ProducerVariant;
|
|
version: ProducerVersion;
|
|
mode: ProducerMode;
|
|
repetition: 1 | 2 | 3;
|
|
model: string;
|
|
host: ProducerHost;
|
|
budgetSeconds: number;
|
|
sourceHash: string;
|
|
skillHash: string;
|
|
}
|
|
|
|
export interface ProducerSourceEntry {
|
|
path: string;
|
|
sha256: string;
|
|
bytes: number;
|
|
}
|
|
|
|
/**
|
|
* This control file is consumed before a producing agent starts. It must never
|
|
* be placed inside the application repository or retained on the producer.
|
|
*/
|
|
export interface ProducerInput {
|
|
schemaVersion: 1;
|
|
cell: ProducerCell;
|
|
/** Exact canonical portable payload: root SKILL.md plus its manifest-listed sections. */
|
|
skill: string;
|
|
source: ProducerSourceEntry[];
|
|
}
|
|
|
|
export interface ProducerArtifactIdentity {
|
|
sha256: string;
|
|
bytes: number;
|
|
}
|
|
|
|
export interface ProducerInstallationIdentity {
|
|
schemaVersion: 1;
|
|
producer: ProducerArtifactIdentity;
|
|
launcher: ProducerArtifactIdentity;
|
|
core: ProducerArtifactIdentity;
|
|
watchdog: ProducerArtifactIdentity;
|
|
/** The adjacent manifest is exactly `<coreSha256>\n`; bind both its bytes and declaration. */
|
|
generation: {
|
|
coreSha256: string;
|
|
manifest: ProducerArtifactIdentity;
|
|
};
|
|
embeddedCatalogs: {
|
|
runtimeRevision: string;
|
|
runtimeBuildRevision: string;
|
|
runtimeSha256: string;
|
|
scannerRevision: string;
|
|
scannerSha256: string;
|
|
};
|
|
identityHash: string;
|
|
}
|
|
|
|
export interface ProducerProviderIdentity {
|
|
schemaVersion: 1;
|
|
family: 'claude' | 'gpt' | 'gemini';
|
|
policyRevision: string;
|
|
executable: ProducerArtifactIdentity;
|
|
argsPrefix: string[];
|
|
version: string;
|
|
identityHash: string;
|
|
}
|
|
|
|
export interface ProducerArtifactInventory {
|
|
schemaVersion: 1;
|
|
root: 'security/cso';
|
|
/** Sorted safe paths relative to root within the retained helper home. */
|
|
entries: ProducerSourceEntry[];
|
|
totalBytes: number;
|
|
identityHash: string;
|
|
}
|
|
|
|
export interface ProducerReceipt {
|
|
schemaVersion: 1;
|
|
cell: ProducerCell;
|
|
inputHash: string;
|
|
installationIdentity: ProducerInstallationIdentity;
|
|
providerIdentity: ProducerProviderIdentity;
|
|
artifacts: ProducerArtifactInventory;
|
|
startedAt: string;
|
|
finishedAt: string;
|
|
status: 'succeeded' | 'failed';
|
|
requestedModel: string;
|
|
modelUsed: string;
|
|
/** Provider-reported when it differs; otherwise the exact CLI model pin. */
|
|
modelIdentitySource: 'provider_reported' | 'requested_pin';
|
|
durationMs: number;
|
|
firstUsefulResultMs: null;
|
|
toolCalls: number;
|
|
output: string;
|
|
outputHash: string;
|
|
usage: {
|
|
/** CLI/provider-reported tokens. Null means the adapter did not report usage. */
|
|
inputTokens: number | null;
|
|
outputTokens: number | null;
|
|
cachedTokens: number | null;
|
|
/** Pricing-table estimate, not a host-billed amount. */
|
|
estimatedCostUSD: number | null;
|
|
};
|
|
error?: { code: string; reason: string };
|
|
receiptHash: string;
|
|
}
|
|
|
|
/** Compact trusted index; raw output remains in the separately retained receipt. */
|
|
export type ProducerReceiptIndex = Omit<ProducerReceipt, 'output' | 'error'> & {
|
|
error?: { code: string };
|
|
};
|
|
|
|
export const sha256 = (value: string | Buffer): string => createHash('sha256').update(value).digest('hex');
|
|
|
|
export function producerInputHash(input: ProducerInput): string {
|
|
return sha256(JSON.stringify(input));
|
|
}
|
|
|
|
export function producerReceiptHash(receipt: Omit<ProducerReceipt, 'receiptHash'>): string {
|
|
return sha256(JSON.stringify(receipt));
|
|
}
|
|
|
|
export function producerInstallationIdentityHash(identity: Omit<ProducerInstallationIdentity, 'identityHash'>): string {
|
|
if (!identity.generation || !identity.generation.manifest || identity.generation.coreSha256 !== identity.core.sha256 ||
|
|
identity.generation.manifest.bytes !== 65 ||
|
|
identity.generation.manifest.sha256 !== sha256(`${identity.generation.coreSha256}\n`)) {
|
|
throw new Error('INVALID_PRODUCER_GENERATION_IDENTITY');
|
|
}
|
|
return sha256(JSON.stringify(identity));
|
|
}
|
|
|
|
export function producerProviderIdentityHash(identity: Omit<ProducerProviderIdentity, 'identityHash'>): string {
|
|
return sha256(JSON.stringify(identity));
|
|
}
|
|
|
|
export function producerArtifactInventoryHash(inventory: Omit<ProducerArtifactInventory, 'identityHash'>): string {
|
|
return sha256(JSON.stringify(inventory));
|
|
}
|