mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-16 09:55:29 +02:00
v1.87.0.0 feat: add verified CSO audits and replayable repair bundles (#2852)
* 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>
This commit is contained in:
co-authored by
OpenAI Codex
parent
9f81911136
commit
4a3c6a8a3c
@@ -0,0 +1,148 @@
|
||||
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));
|
||||
}
|
||||
Reference in New Issue
Block a user