owlrunkit 0.19.1 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +71 -0
- package/docs/architecture/OWLCODA_RUNKIT_0191_PROFILE_RECONCILE_PATCH_PRODUCT_DECISION_20260813.md +11 -5
- package/docs/architecture/OWLCODA_RUNKIT_0192_FORMAL_USABILITY_PRODUCT_DECISION_20260813.md +141 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +50 -7
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/package.json +1 -1
- package/packages/attest/distribution-manifest-v1.json +5 -0
- package/packages/attest/src/quick.mjs +37 -4
- package/registry-release-policy-v1.json +5 -5
- package/sbom.spdx.json +5 -5
- package/scripts/runkit-contract/core-contract.mjs +35 -2
- package/scripts/runkit-contract/efficiency-metrics.mjs +9 -7
- package/scripts/runkit-contract/formal-preflight.mjs +352 -0
- package/scripts/runkit-contract/formal-supplemental-evidence.mjs +713 -0
- package/scripts/runkit-contract/formal-workflow.mjs +529 -59
- package/scripts/runkit-contract/onboarding-doctor.mjs +32 -13
- package/scripts/runkit-contract/project-cli-resolver.mjs +30 -3
- package/scripts/runkit-contract/project-external-delivery.mjs +16 -9
- package/scripts/runkit-contract/quick-attest.mjs +24 -0
- package/scripts/runkit-contract/runkit-cli.mjs +365 -49
- package/scripts/runkit-contract/schemas/formal-check-v2.schema.json +231 -0
- package/scripts/runkit-contract/schemas/formal-envelope-preflight-v1.schema.json +212 -0
- package/scripts/runkit-contract/schemas/formal-evidence-summary-v1.schema.json +114 -0
- package/scripts/runkit-contract/schemas/formal-supplemental-evidence-v1.schema.json +103 -0
- package/scripts/runkit-contract/schemas/team-project-event-v5.schema.json +89 -0
- package/scripts/runkit-contract/schemas/team-project-status-v3.schema.json +173 -0
- package/scripts/runkit-contract/snapshot.mjs +125 -5
- package/scripts/runkit-contract/source-candidate.mjs +271 -69
- package/scripts/runkit-contract/sync-release-identity.mjs +39 -4
- package/scripts/runkit-contract/team-project-successor.mjs +7 -4
- package/scripts/runkit-contract/team-project.mjs +440 -28
- package/scripts/runkit-contract/usage-mode.mjs +9 -3
- package/scripts/runkit-contract/verification-envelope.mjs +425 -37
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
validateCoreArtifact,
|
|
14
14
|
} from "./core-contract.mjs";
|
|
15
15
|
import { runFinalize } from "./finalize.mjs";
|
|
16
|
+
import { preflightFormalEnvelopeV1 } from "./formal-preflight.mjs";
|
|
17
|
+
import { readWorkspaceJsonBounded } from "./onboarding-doctor.mjs";
|
|
16
18
|
import { derivedVerificationContext } from "./lifecycle-orchestration.mjs";
|
|
17
19
|
import { withControlTransaction } from "./lease-lifecycle.mjs";
|
|
18
20
|
import {
|
|
@@ -30,12 +32,18 @@ import {
|
|
|
30
32
|
} from "./snapshot.mjs";
|
|
31
33
|
import {
|
|
32
34
|
freezeSourceCandidateWithinControlTransactionV2,
|
|
35
|
+
previewSourceCandidateWithinControlTransactionV2,
|
|
36
|
+
verifySourceCandidateDetailsV2,
|
|
33
37
|
verifySourceCandidateV2,
|
|
34
38
|
} from "./source-candidate.mjs";
|
|
35
39
|
import { validateReceiptLineage } from "./receipt-lineage.mjs";
|
|
36
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
validateVerificationContext,
|
|
42
|
+
verificationContextFingerprint,
|
|
43
|
+
} from "./verification-context.mjs";
|
|
37
44
|
import {
|
|
38
45
|
runVerificationEnvelopeV1,
|
|
46
|
+
validateEnvelopeSourceCandidateBoundaryV1,
|
|
39
47
|
validateVerificationEnvelopeV1,
|
|
40
48
|
verifyVerificationEnvelopeReceiptV1,
|
|
41
49
|
} from "./verification-envelope.mjs";
|
|
@@ -126,6 +134,17 @@ function canonicalJson(value) {
|
|
|
126
134
|
return encoded;
|
|
127
135
|
}
|
|
128
136
|
|
|
137
|
+
function formalCheckHash(value) {
|
|
138
|
+
return `sha256:${sha256(canonicalJson(value))}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function hasExactKeys(value, keys) {
|
|
142
|
+
return Boolean(value)
|
|
143
|
+
&& typeof value === "object"
|
|
144
|
+
&& !Array.isArray(value)
|
|
145
|
+
&& canonicalJson(Object.keys(value).sort()) === canonicalJson([...keys].sort());
|
|
146
|
+
}
|
|
147
|
+
|
|
129
148
|
function readRegularJson(filePath, label) {
|
|
130
149
|
const stat = lstatSync(filePath);
|
|
131
150
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -137,6 +156,20 @@ function readRegularJson(filePath, label) {
|
|
|
137
156
|
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
138
157
|
}
|
|
139
158
|
|
|
159
|
+
function readWorkspaceRegularJson(workspaceRoot, filePath, label) {
|
|
160
|
+
try {
|
|
161
|
+
return readWorkspaceJsonBounded(
|
|
162
|
+
workspaceRoot,
|
|
163
|
+
relativeToWorkspace(workspaceRoot, filePath),
|
|
164
|
+
{ maxBytes: 64 * 1024 * 1024, maxNodes: 2_000_000 },
|
|
165
|
+
);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throw new Error(`${label} must be bounded regular JSON inside the workspace.`, {
|
|
168
|
+
cause: error,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
140
173
|
function writeOrResumeExactJson(filePath, value, label) {
|
|
141
174
|
if (!existsSync(filePath)) {
|
|
142
175
|
writeJsonExclusiveAtomically(filePath, value);
|
|
@@ -335,7 +368,224 @@ export function validateLegacyVerificationSideEffectsV1({ commandArgv }) {
|
|
|
335
368
|
};
|
|
336
369
|
}
|
|
337
370
|
|
|
338
|
-
|
|
371
|
+
const FORMAL_CHECK_V2_KEYS = [
|
|
372
|
+
"schemaVersion",
|
|
373
|
+
"runId",
|
|
374
|
+
"checkId",
|
|
375
|
+
"sequence",
|
|
376
|
+
"status",
|
|
377
|
+
"candidatePath",
|
|
378
|
+
"candidateSha256",
|
|
379
|
+
"payloadSha256",
|
|
380
|
+
"sourceFingerprint",
|
|
381
|
+
"verificationContext",
|
|
382
|
+
"verificationContextFingerprint",
|
|
383
|
+
"snapshotRequestPath",
|
|
384
|
+
"snapshotPath",
|
|
385
|
+
"commandExitCode",
|
|
386
|
+
"verificationCommandPolicy",
|
|
387
|
+
"envelopePath",
|
|
388
|
+
"envelopeSha256",
|
|
389
|
+
"envelopeReceiptPath",
|
|
390
|
+
"envelopeReceiptSha256",
|
|
391
|
+
"envelopeFormalEligible",
|
|
392
|
+
"failureCategory",
|
|
393
|
+
"failureDetail",
|
|
394
|
+
"finalized",
|
|
395
|
+
"authorizationGranted",
|
|
396
|
+
"formalCheckSha256",
|
|
397
|
+
];
|
|
398
|
+
|
|
399
|
+
const FORMAL_POLICY_V2_KEYS = [
|
|
400
|
+
"schemaVersion",
|
|
401
|
+
"mode",
|
|
402
|
+
"riskClassification",
|
|
403
|
+
"profileCommandIds",
|
|
404
|
+
"envelopeSha256",
|
|
405
|
+
"envelopeReceiptSha256",
|
|
406
|
+
"authorizationGranted",
|
|
407
|
+
];
|
|
408
|
+
|
|
409
|
+
function expectedFormalPath(workspaceRoot, executionRoot, ...segments) {
|
|
410
|
+
return relativeToWorkspace(
|
|
411
|
+
workspaceRoot,
|
|
412
|
+
path.join(executionRoot, ...segments),
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function validateFormalCheckV2({
|
|
417
|
+
workspaceRoot,
|
|
418
|
+
executionRoot,
|
|
419
|
+
runId,
|
|
420
|
+
fileName,
|
|
421
|
+
check,
|
|
422
|
+
}) {
|
|
423
|
+
const checkId = path.basename(fileName, ".json");
|
|
424
|
+
const { formalCheckSha256, ...checkBody } = check ?? {};
|
|
425
|
+
if (
|
|
426
|
+
!hasExactKeys(check, FORMAL_CHECK_V2_KEYS)
|
|
427
|
+
|| check.schemaVersion !== "OwlCodaRunKitFormalCheckV2"
|
|
428
|
+
|| check.runId !== runId
|
|
429
|
+
|| check.checkId !== checkId
|
|
430
|
+
|| !Number.isSafeInteger(check.sequence)
|
|
431
|
+
|| check.sequence < 1
|
|
432
|
+
|| !new Set(["formal_check_passed", "formal_check_failed"]).has(check.status)
|
|
433
|
+
|| check.finalized !== false
|
|
434
|
+
|| check.authorizationGranted !== false
|
|
435
|
+
|| !/^sha256:[a-f0-9]{64}$/u.test(formalCheckSha256)
|
|
436
|
+
|| formalCheckSha256 !== formalCheckHash(checkBody)
|
|
437
|
+
) {
|
|
438
|
+
throw new Error(`Formal Check V2 contract is invalid: ${fileName}`);
|
|
439
|
+
}
|
|
440
|
+
const expected = {
|
|
441
|
+
candidatePath: expectedFormalPath(
|
|
442
|
+
workspaceRoot,
|
|
443
|
+
executionRoot,
|
|
444
|
+
"source-candidates",
|
|
445
|
+
`${checkId}.json`,
|
|
446
|
+
),
|
|
447
|
+
snapshotRequestPath: expectedFormalPath(
|
|
448
|
+
workspaceRoot,
|
|
449
|
+
executionRoot,
|
|
450
|
+
"formal-check-requests",
|
|
451
|
+
`${checkId}.json`,
|
|
452
|
+
),
|
|
453
|
+
snapshotPath: expectedFormalPath(
|
|
454
|
+
workspaceRoot,
|
|
455
|
+
executionRoot,
|
|
456
|
+
"snapshots",
|
|
457
|
+
`${checkId}-snapshot.json`,
|
|
458
|
+
),
|
|
459
|
+
envelopePath: expectedFormalPath(
|
|
460
|
+
workspaceRoot,
|
|
461
|
+
executionRoot,
|
|
462
|
+
"formal-envelopes",
|
|
463
|
+
`${checkId}.json`,
|
|
464
|
+
),
|
|
465
|
+
envelopeReceiptPath: expectedFormalPath(
|
|
466
|
+
workspaceRoot,
|
|
467
|
+
executionRoot,
|
|
468
|
+
"verification-envelopes",
|
|
469
|
+
checkId,
|
|
470
|
+
"verification-envelope-receipt.json",
|
|
471
|
+
),
|
|
472
|
+
};
|
|
473
|
+
for (const [field, expectedPath] of Object.entries(expected)) {
|
|
474
|
+
if (check[field] !== expectedPath) {
|
|
475
|
+
throw new Error(`Formal Check V2 ${field} is invalid: ${fileName}`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const candidate = verifySourceCandidateDetailsV2({
|
|
479
|
+
workspaceRoot,
|
|
480
|
+
candidatePath: check.candidatePath,
|
|
481
|
+
requireCurrentWorkspace: false,
|
|
482
|
+
});
|
|
483
|
+
const candidateDocument = candidate.candidateDocument;
|
|
484
|
+
if (
|
|
485
|
+
candidate.gate.status !== "valid"
|
|
486
|
+
|| candidateDocument === null
|
|
487
|
+
|| candidateDocument.runId !== runId
|
|
488
|
+
|| candidateDocument.candidateId !== checkId
|
|
489
|
+
|| candidateDocument.candidateSha256 !== check.candidateSha256
|
|
490
|
+
|| candidateDocument.payload.sha256 !== check.payloadSha256
|
|
491
|
+
|| candidateDocument.sourceFingerprint.sha256 !== check.sourceFingerprint
|
|
492
|
+
) {
|
|
493
|
+
throw new Error(`Formal Check V2 candidate binding is invalid: ${fileName}`);
|
|
494
|
+
}
|
|
495
|
+
const context = validateVerificationContext(check.verificationContext);
|
|
496
|
+
if (
|
|
497
|
+
!context.valid
|
|
498
|
+
|| verificationContextFingerprint(check.verificationContext)
|
|
499
|
+
!== check.verificationContextFingerprint
|
|
500
|
+
) {
|
|
501
|
+
throw new Error(`Formal Check V2 verification context is invalid: ${fileName}`);
|
|
502
|
+
}
|
|
503
|
+
if (
|
|
504
|
+
!hasExactKeys(check.verificationCommandPolicy, FORMAL_POLICY_V2_KEYS)
|
|
505
|
+
|| check.verificationCommandPolicy.schemaVersion
|
|
506
|
+
!== "OwlCodaRunKitFormalVerificationCommandPolicyV1"
|
|
507
|
+
|| check.verificationCommandPolicy.mode !== "verification_envelope_v1"
|
|
508
|
+
|| check.verificationCommandPolicy.riskClassification
|
|
509
|
+
!== "enforced_verification_envelope"
|
|
510
|
+
|| canonicalJson(check.verificationCommandPolicy.profileCommandIds) !== "[]"
|
|
511
|
+
|| check.verificationCommandPolicy.envelopeSha256 !== check.envelopeSha256
|
|
512
|
+
|| check.verificationCommandPolicy.envelopeReceiptSha256
|
|
513
|
+
!== check.envelopeReceiptSha256
|
|
514
|
+
|| check.verificationCommandPolicy.authorizationGranted !== false
|
|
515
|
+
) {
|
|
516
|
+
throw new Error(`Formal Check V2 command policy is invalid: ${fileName}`);
|
|
517
|
+
}
|
|
518
|
+
const envelope = readWorkspaceRegularJson(
|
|
519
|
+
workspaceRoot,
|
|
520
|
+
path.join(workspaceRoot, check.envelopePath),
|
|
521
|
+
"Formal Verification Envelope",
|
|
522
|
+
);
|
|
523
|
+
const validatedEnvelope = validateVerificationEnvelopeV1({
|
|
524
|
+
workspaceRoot,
|
|
525
|
+
envelope,
|
|
526
|
+
requireCurrentEnvironment: false,
|
|
527
|
+
});
|
|
528
|
+
if (validatedEnvelope.envelopeSha256 !== check.envelopeSha256) {
|
|
529
|
+
throw new Error(`Formal Check V2 envelope binding is invalid: ${fileName}`);
|
|
530
|
+
}
|
|
531
|
+
const envelopeReceiptPath = path.join(workspaceRoot, check.envelopeReceiptPath);
|
|
532
|
+
const envelopeReceipt = readWorkspaceRegularJson(
|
|
533
|
+
workspaceRoot,
|
|
534
|
+
envelopeReceiptPath,
|
|
535
|
+
"Verification Envelope receipt",
|
|
536
|
+
);
|
|
537
|
+
const verifiedEnvelope = verifyVerificationEnvelopeReceiptV1({
|
|
538
|
+
workspaceRoot,
|
|
539
|
+
receiptPath: envelopeReceiptPath,
|
|
540
|
+
requireCurrentSource: false,
|
|
541
|
+
});
|
|
542
|
+
if (
|
|
543
|
+
verifiedEnvelope.receiptSha256 !== check.envelopeReceiptSha256
|
|
544
|
+
|| verifiedEnvelope.envelopeSha256 !== check.envelopeSha256
|
|
545
|
+
|| verifiedEnvelope.formalEligible !== check.envelopeFormalEligible
|
|
546
|
+
) {
|
|
547
|
+
throw new Error(`Formal Check V2 envelope receipt binding is invalid: ${fileName}`);
|
|
548
|
+
}
|
|
549
|
+
const snapshot = readWorkspaceRegularJson(
|
|
550
|
+
workspaceRoot,
|
|
551
|
+
path.join(workspaceRoot, check.snapshotPath),
|
|
552
|
+
"Formal snapshot",
|
|
553
|
+
);
|
|
554
|
+
const snapshotGate = verifySnapshotEvidence({
|
|
555
|
+
workspaceRoot,
|
|
556
|
+
runId,
|
|
557
|
+
snapshot,
|
|
558
|
+
requirePassed: false,
|
|
559
|
+
});
|
|
560
|
+
if (
|
|
561
|
+
!snapshotGate.valid
|
|
562
|
+
|| snapshot.snapshotId !== `${checkId}-snapshot`
|
|
563
|
+
|| snapshot.verificationContextFingerprint !== check.verificationContextFingerprint
|
|
564
|
+
|| snapshot.command.exitCode !== check.commandExitCode
|
|
565
|
+
|| snapshot.command.exitCode !== (envelopeReceipt.formalEligible ? 0 : 2)
|
|
566
|
+
) {
|
|
567
|
+
throw new Error(`Formal Check V2 snapshot binding is invalid: ${fileName}`);
|
|
568
|
+
}
|
|
569
|
+
const expectedStatus = snapshot.status === "snapshot_passed"
|
|
570
|
+
&& envelopeReceipt.formalEligible
|
|
571
|
+
? "formal_check_passed"
|
|
572
|
+
: "formal_check_failed";
|
|
573
|
+
const expectedFailure = classifyFormalEnvelopeFailureV1({
|
|
574
|
+
envelopeReceipt,
|
|
575
|
+
snapshotStatus: snapshot.status,
|
|
576
|
+
finalStatus: expectedStatus,
|
|
577
|
+
});
|
|
578
|
+
if (
|
|
579
|
+
check.status !== expectedStatus
|
|
580
|
+
|| check.failureCategory !== expectedFailure.failureCategory
|
|
581
|
+
|| check.failureDetail !== expectedFailure.failureDetail
|
|
582
|
+
) {
|
|
583
|
+
throw new Error(`Formal Check V2 derived fields are invalid: ${fileName}`);
|
|
584
|
+
}
|
|
585
|
+
return check;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function readChecks(workspaceRoot, executionRoot, runId) {
|
|
339
589
|
const root = checkRoot(executionRoot);
|
|
340
590
|
if (!existsSync(root)) return [];
|
|
341
591
|
const stat = lstatSync(root);
|
|
@@ -349,11 +599,27 @@ function readChecks(executionRoot) {
|
|
|
349
599
|
if (entry.isSymbolicLink() || !entry.isFile()) {
|
|
350
600
|
throw new Error(`Formal check must be a regular file: ${entry.name}`);
|
|
351
601
|
}
|
|
352
|
-
const value =
|
|
602
|
+
const value = readWorkspaceRegularJson(
|
|
603
|
+
workspaceRoot,
|
|
604
|
+
path.join(root, entry.name),
|
|
605
|
+
"Formal check",
|
|
606
|
+
);
|
|
607
|
+
if (value.schemaVersion === "OwlCodaRunKitFormalCheckV2") {
|
|
608
|
+
return validateFormalCheckV2({
|
|
609
|
+
workspaceRoot,
|
|
610
|
+
executionRoot,
|
|
611
|
+
runId,
|
|
612
|
+
fileName: entry.name,
|
|
613
|
+
check: value,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
353
616
|
if (
|
|
354
617
|
value.schemaVersion !== "OwlCodaRunKitFormalCheckV1"
|
|
618
|
+
|| value.runId !== runId
|
|
619
|
+
|| value.checkId !== path.basename(entry.name, ".json")
|
|
355
620
|
|| !Number.isSafeInteger(value.sequence)
|
|
356
621
|
|| value.sequence < 1
|
|
622
|
+
|| value.authorizationGranted !== false
|
|
357
623
|
) {
|
|
358
624
|
throw new Error(`Formal check contract is invalid: ${entry.name}`);
|
|
359
625
|
}
|
|
@@ -362,6 +628,60 @@ function readChecks(executionRoot) {
|
|
|
362
628
|
.sort((left, right) => left.sequence - right.sequence);
|
|
363
629
|
}
|
|
364
630
|
|
|
631
|
+
export function readFormalChecksV1({ workspaceRoot, executionRoot, runId }) {
|
|
632
|
+
return readChecks(realpathSync(workspaceRoot), executionRoot, runId);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
export function classifyFormalEnvelopeFailureV1({
|
|
636
|
+
envelopeReceipt,
|
|
637
|
+
snapshotStatus,
|
|
638
|
+
finalStatus,
|
|
639
|
+
}) {
|
|
640
|
+
if (finalStatus === "formal_check_passed") {
|
|
641
|
+
return { failureCategory: null, failureDetail: null };
|
|
642
|
+
}
|
|
643
|
+
if (
|
|
644
|
+
envelopeReceipt.status === "policy_backend_unavailable"
|
|
645
|
+
|| envelopeReceipt.commandExecuted === false
|
|
646
|
+
) {
|
|
647
|
+
return {
|
|
648
|
+
failureCategory: "envelope_capability_missing",
|
|
649
|
+
failureDetail: envelopeReceipt.backend?.reason ?? "enforcement_backend_unavailable",
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
const phases = envelopeReceipt.phases ?? [];
|
|
653
|
+
const launched = phases.find(phase => phase.launchError !== null && phase.launchError !== undefined);
|
|
654
|
+
if (launched) {
|
|
655
|
+
return {
|
|
656
|
+
failureCategory: "toolchain_resolution_failed",
|
|
657
|
+
failureDetail: `phase_${launched.name}_launch_failed`,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
if (snapshotStatus === "invalidated_by_target_write") {
|
|
661
|
+
return {
|
|
662
|
+
failureCategory: "envelope_capability_missing",
|
|
663
|
+
failureDetail: "verification_evidence_snapshot_not_current",
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if (
|
|
667
|
+
phases.some(phase => phase.timedOut || phase.outputOverflow)
|
|
668
|
+
|| envelopeReceipt.source?.unchanged === false
|
|
669
|
+
|| envelopeReceipt.cleanup?.teardownCompleted === false
|
|
670
|
+
|| (envelopeReceipt.cleanup?.terminatedProcessIds?.length ?? 0) > 0
|
|
671
|
+
|| (envelopeReceipt.cleanup?.remainingProcessIds?.length ?? 0) > 0
|
|
672
|
+
|| (envelopeReceipt.cleanup?.issues?.length ?? 0) > 0
|
|
673
|
+
) {
|
|
674
|
+
return {
|
|
675
|
+
failureCategory: "envelope_capability_missing",
|
|
676
|
+
failureDetail: "verification_envelope_constraints_not_satisfied",
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
failureCategory: "source_check_failed",
|
|
681
|
+
failureDetail: "verification_command_returned_nonzero",
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
365
685
|
function resumeOrFreezeCandidate({
|
|
366
686
|
workspaceRoot,
|
|
367
687
|
executionRoot,
|
|
@@ -375,30 +695,41 @@ function resumeOrFreezeCandidate({
|
|
|
375
695
|
`${checkId}.json`,
|
|
376
696
|
);
|
|
377
697
|
if (!existsSync(candidatePath)) {
|
|
698
|
+
const candidate = freezeSourceCandidateWithinControlTransactionV2({
|
|
699
|
+
workspaceRoot,
|
|
700
|
+
runId,
|
|
701
|
+
workItemId,
|
|
702
|
+
candidateId: checkId,
|
|
703
|
+
});
|
|
704
|
+
if (candidate.status !== "source_candidate_frozen") {
|
|
705
|
+
return { candidate, candidateDocument: null, resumed: false };
|
|
706
|
+
}
|
|
707
|
+
const verified = verifySourceCandidateDetailsV2({
|
|
708
|
+
workspaceRoot,
|
|
709
|
+
candidatePath: candidate.candidatePath,
|
|
710
|
+
});
|
|
711
|
+
if (verified.gate.status !== "valid" || verified.candidateDocument === null) {
|
|
712
|
+
throw new Error(`New Formal source candidate failed verification: ${checkId}`);
|
|
713
|
+
}
|
|
378
714
|
return {
|
|
379
|
-
candidate
|
|
380
|
-
|
|
381
|
-
runId,
|
|
382
|
-
workItemId,
|
|
383
|
-
candidateId: checkId,
|
|
384
|
-
}),
|
|
715
|
+
candidate,
|
|
716
|
+
candidateDocument: verified.candidateDocument,
|
|
385
717
|
resumed: false,
|
|
386
718
|
};
|
|
387
719
|
}
|
|
388
|
-
const candidateDocument = readRegularJson(
|
|
389
|
-
candidatePath,
|
|
390
|
-
"Formal source candidate",
|
|
391
|
-
);
|
|
392
720
|
const candidateRelativePath = relativeToWorkspace(
|
|
393
721
|
workspaceRoot,
|
|
394
722
|
candidatePath,
|
|
395
723
|
);
|
|
396
|
-
const
|
|
724
|
+
const verified = verifySourceCandidateDetailsV2({
|
|
397
725
|
workspaceRoot,
|
|
398
726
|
candidatePath: candidateRelativePath,
|
|
399
727
|
});
|
|
728
|
+
const gate = verified.gate;
|
|
729
|
+
const candidateDocument = verified.candidateDocument;
|
|
400
730
|
if (
|
|
401
731
|
gate.status !== "valid"
|
|
732
|
+
|| candidateDocument === null
|
|
402
733
|
|| candidateDocument.runId !== runId
|
|
403
734
|
|| candidateDocument.candidateId !== checkId
|
|
404
735
|
|| candidateDocument.discovery?.fromLease !== workItemId
|
|
@@ -421,6 +752,7 @@ function resumeOrFreezeCandidate({
|
|
|
421
752
|
ownedPaths: [...candidateDocument.sourceManifest.ownedPaths],
|
|
422
753
|
authorizationGranted: false,
|
|
423
754
|
},
|
|
755
|
+
candidateDocument,
|
|
424
756
|
resumed: true,
|
|
425
757
|
};
|
|
426
758
|
}
|
|
@@ -464,6 +796,7 @@ function resumeSnapshot({
|
|
|
464
796
|
workspaceRoot,
|
|
465
797
|
runId,
|
|
466
798
|
snapshot,
|
|
799
|
+
requirePassed: false,
|
|
467
800
|
});
|
|
468
801
|
if (
|
|
469
802
|
!evidence.valid
|
|
@@ -577,7 +910,7 @@ function recordFormalCheckWithinControlTransaction({
|
|
|
577
910
|
? readRegularJson(receiptPath, "Formal check receipt")
|
|
578
911
|
: null;
|
|
579
912
|
const sequence = existingReceipt?.sequence
|
|
580
|
-
?? readChecks(executionRoot).length + 1;
|
|
913
|
+
?? readChecks(root, executionRoot, runId).length + 1;
|
|
581
914
|
const status = snapshot.status === "snapshot_passed"
|
|
582
915
|
? "formal_check_passed"
|
|
583
916
|
: "formal_check_failed";
|
|
@@ -646,11 +979,137 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
646
979
|
const root = realpathSync(workspaceRoot);
|
|
647
980
|
const { executionRoot, pinGate } = loadActiveExecution(root, runId);
|
|
648
981
|
if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
|
|
649
|
-
const
|
|
982
|
+
const structurallyValidatedEnvelope = validateVerificationEnvelopeV1({
|
|
650
983
|
workspaceRoot: root,
|
|
651
984
|
envelope,
|
|
985
|
+
requireCurrentEnvironment: false,
|
|
652
986
|
});
|
|
653
987
|
const receiptPath = path.join(checkRoot(executionRoot), `${checkId}.json`);
|
|
988
|
+
if (existsSync(receiptPath)) {
|
|
989
|
+
const existing = readChecks(root, executionRoot, runId)
|
|
990
|
+
.find(check => check.checkId === checkId);
|
|
991
|
+
if (
|
|
992
|
+
existing?.schemaVersion !== "OwlCodaRunKitFormalCheckV2"
|
|
993
|
+
|| existing.envelopeSha256 !== structurallyValidatedEnvelope.envelopeSha256
|
|
994
|
+
) {
|
|
995
|
+
throw new Error(`Existing Formal check differs from the resumed command: ${checkId}`);
|
|
996
|
+
}
|
|
997
|
+
const current = verifySourceCandidateDetailsV2({
|
|
998
|
+
workspaceRoot: root,
|
|
999
|
+
candidatePath: existing.candidatePath,
|
|
1000
|
+
});
|
|
1001
|
+
if (
|
|
1002
|
+
current.gate.status !== "valid"
|
|
1003
|
+
|| current.candidateDocument?.discovery?.fromLease !== workItemId
|
|
1004
|
+
) {
|
|
1005
|
+
throw new Error(`Existing Formal check source differs from the resumed command: ${checkId}`);
|
|
1006
|
+
}
|
|
1007
|
+
return {
|
|
1008
|
+
...existing,
|
|
1009
|
+
exitCode: existing.status === "formal_check_passed" ? 0 : 2,
|
|
1010
|
+
checkReceiptPath: relativeToWorkspace(root, receiptPath),
|
|
1011
|
+
resumed: true,
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
const envelopePath = path.join(
|
|
1015
|
+
executionRoot,
|
|
1016
|
+
"formal-envelopes",
|
|
1017
|
+
`${checkId}.json`,
|
|
1018
|
+
);
|
|
1019
|
+
if (existsSync(envelopePath)) {
|
|
1020
|
+
const existingEnvelope = readRegularJson(
|
|
1021
|
+
envelopePath,
|
|
1022
|
+
"Formal Verification Envelope",
|
|
1023
|
+
);
|
|
1024
|
+
if (
|
|
1025
|
+
canonicalJson(existingEnvelope)
|
|
1026
|
+
!== canonicalJson(structurallyValidatedEnvelope.envelope)
|
|
1027
|
+
) {
|
|
1028
|
+
throw new Error("Existing Formal Verification Envelope differs from the resumed command.");
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
const candidatePath = path.join(
|
|
1032
|
+
executionRoot,
|
|
1033
|
+
"source-candidates",
|
|
1034
|
+
`${checkId}.json`,
|
|
1035
|
+
);
|
|
1036
|
+
const requestPath = path.join(
|
|
1037
|
+
executionRoot,
|
|
1038
|
+
"formal-check-requests",
|
|
1039
|
+
`${checkId}.json`,
|
|
1040
|
+
);
|
|
1041
|
+
const snapshotPath = path.join(
|
|
1042
|
+
executionRoot,
|
|
1043
|
+
"snapshots",
|
|
1044
|
+
`${checkId}-snapshot.json`,
|
|
1045
|
+
);
|
|
1046
|
+
const envelopeReceiptPath = path.join(
|
|
1047
|
+
executionRoot,
|
|
1048
|
+
"verification-envelopes",
|
|
1049
|
+
checkId,
|
|
1050
|
+
"verification-envelope-receipt.json",
|
|
1051
|
+
);
|
|
1052
|
+
if (
|
|
1053
|
+
!existsSync(candidatePath)
|
|
1054
|
+
&& [requestPath, snapshotPath, envelopeReceiptPath].some(existsSync)
|
|
1055
|
+
) {
|
|
1056
|
+
throw new Error("Incomplete Formal check artifacts require a new check id.");
|
|
1057
|
+
}
|
|
1058
|
+
if (existsSync(snapshotPath) && !existsSync(requestPath)) {
|
|
1059
|
+
throw new Error("Incomplete Formal snapshot artifacts require a new check id.");
|
|
1060
|
+
}
|
|
1061
|
+
const preflight = preflightFormalEnvelopeV1({
|
|
1062
|
+
workspaceRoot: root,
|
|
1063
|
+
envelope: structurallyValidatedEnvelope.envelope,
|
|
1064
|
+
});
|
|
1065
|
+
if (preflight.status === "blocked") return preflight;
|
|
1066
|
+
const validatedEnvelope = validateVerificationEnvelopeV1({
|
|
1067
|
+
workspaceRoot: root,
|
|
1068
|
+
envelope: structurallyValidatedEnvelope.envelope,
|
|
1069
|
+
});
|
|
1070
|
+
const preview = previewSourceCandidateWithinControlTransactionV2({
|
|
1071
|
+
workspaceRoot: root,
|
|
1072
|
+
runId,
|
|
1073
|
+
workItemId,
|
|
1074
|
+
});
|
|
1075
|
+
if (preview.status !== "source_candidate_previewed") return preview;
|
|
1076
|
+
validateEnvelopeSourceCandidateBoundaryV1({
|
|
1077
|
+
envelope: validatedEnvelope.envelope,
|
|
1078
|
+
sourceManifest: preview.sourceManifest,
|
|
1079
|
+
});
|
|
1080
|
+
const context = derivedVerificationContext(root);
|
|
1081
|
+
const commandArgv = [
|
|
1082
|
+
realpathSync(process.execPath),
|
|
1083
|
+
VERIFICATION_ENVELOPE_CHECKER,
|
|
1084
|
+
"--workspace",
|
|
1085
|
+
root,
|
|
1086
|
+
"--receipt",
|
|
1087
|
+
envelopeReceiptPath,
|
|
1088
|
+
];
|
|
1089
|
+
const buildSnapshotRequest = sourceManifest => ({
|
|
1090
|
+
schemaVersion: "OwlCodaRunKitSnapshotRequestV1",
|
|
1091
|
+
snapshotId: `${checkId}-snapshot`,
|
|
1092
|
+
mode: "project",
|
|
1093
|
+
targetRoot: root,
|
|
1094
|
+
cwd: ".",
|
|
1095
|
+
executable: commandArgv[0],
|
|
1096
|
+
argv: commandArgv.slice(1),
|
|
1097
|
+
launcherVersion: "owlrunkit-formal-envelope-v1",
|
|
1098
|
+
toolVersions: structuredClone(context.toolchains),
|
|
1099
|
+
selectedPaths: sourceManifest.entries
|
|
1100
|
+
.filter(entry => entry.operation !== "deleted")
|
|
1101
|
+
.map(entry => entry.path)
|
|
1102
|
+
.sort(),
|
|
1103
|
+
statusMode: "porcelain-v1-z-untracked-all-runkit-excluded",
|
|
1104
|
+
verificationContext: context,
|
|
1105
|
+
});
|
|
1106
|
+
const previewRequest = buildSnapshotRequest(preview.sourceManifest);
|
|
1107
|
+
if (existsSync(requestPath)) {
|
|
1108
|
+
const existingRequest = readRegularJson(requestPath, "Formal check request");
|
|
1109
|
+
if (canonicalJson(existingRequest) !== canonicalJson(previewRequest)) {
|
|
1110
|
+
throw new Error("Existing Formal check request differs from the resumed command.");
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
654
1113
|
const candidateResult = resumeOrFreezeCandidate({
|
|
655
1114
|
workspaceRoot: root,
|
|
656
1115
|
executionRoot,
|
|
@@ -661,12 +1120,15 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
661
1120
|
const candidate = candidateResult.candidate;
|
|
662
1121
|
if (candidate.status !== "source_candidate_frozen") return candidate;
|
|
663
1122
|
hooks.afterCandidatePersist?.();
|
|
664
|
-
const candidateDocument =
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
);
|
|
1123
|
+
const candidateDocument = candidateResult.candidateDocument;
|
|
1124
|
+
validateEnvelopeSourceCandidateBoundaryV1({
|
|
1125
|
+
envelope: validatedEnvelope.envelope,
|
|
1126
|
+
sourceManifest: candidateDocument.sourceManifest,
|
|
1127
|
+
});
|
|
1128
|
+
const request = buildSnapshotRequest(candidateDocument.sourceManifest);
|
|
1129
|
+
if (canonicalJson(request) !== canonicalJson(previewRequest)) {
|
|
1130
|
+
throw new Error("Formal source changed after preflight; create a new check id.");
|
|
1131
|
+
}
|
|
670
1132
|
const envelopeResult = writeOrResumeExactJson(
|
|
671
1133
|
envelopePath,
|
|
672
1134
|
validatedEnvelope.envelope,
|
|
@@ -683,14 +1145,6 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
683
1145
|
artifactRoot: envelopeArtifactRoot,
|
|
684
1146
|
});
|
|
685
1147
|
hooks.afterEnvelopePersist?.();
|
|
686
|
-
const commandArgv = [
|
|
687
|
-
realpathSync(process.execPath),
|
|
688
|
-
VERIFICATION_ENVELOPE_CHECKER,
|
|
689
|
-
"--workspace",
|
|
690
|
-
root,
|
|
691
|
-
"--receipt",
|
|
692
|
-
envelopeReceipt.receiptPath,
|
|
693
|
-
];
|
|
694
1148
|
const verificationCommandPolicy = {
|
|
695
1149
|
schemaVersion: "OwlCodaRunKitFormalVerificationCommandPolicyV1",
|
|
696
1150
|
mode: "verification_envelope_v1",
|
|
@@ -702,29 +1156,6 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
702
1156
|
envelopeReceiptSha256: envelopeReceipt.receiptSha256,
|
|
703
1157
|
authorizationGranted: false,
|
|
704
1158
|
};
|
|
705
|
-
const context = derivedVerificationContext(root);
|
|
706
|
-
const request = {
|
|
707
|
-
schemaVersion: "OwlCodaRunKitSnapshotRequestV1",
|
|
708
|
-
snapshotId: `${checkId}-snapshot`,
|
|
709
|
-
mode: "project",
|
|
710
|
-
targetRoot: root,
|
|
711
|
-
cwd: ".",
|
|
712
|
-
executable: verificationCommandPolicy.executable,
|
|
713
|
-
argv: verificationCommandPolicy.argv,
|
|
714
|
-
launcherVersion: "owlrunkit-formal-envelope-v1",
|
|
715
|
-
toolVersions: structuredClone(context.toolchains),
|
|
716
|
-
selectedPaths: candidateDocument.sourceManifest.entries
|
|
717
|
-
.filter((entry) => entry.operation !== "deleted")
|
|
718
|
-
.map((entry) => entry.path)
|
|
719
|
-
.sort(),
|
|
720
|
-
statusMode: "porcelain-v1-z-untracked-all-runkit-excluded",
|
|
721
|
-
verificationContext: context,
|
|
722
|
-
};
|
|
723
|
-
const requestPath = path.join(
|
|
724
|
-
executionRoot,
|
|
725
|
-
"formal-check-requests",
|
|
726
|
-
`${checkId}.json`,
|
|
727
|
-
);
|
|
728
1159
|
const requestResult = writeOrResumeExactJson(
|
|
729
1160
|
requestPath,
|
|
730
1161
|
request,
|
|
@@ -745,13 +1176,18 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
745
1176
|
? readRegularJson(receiptPath, "Formal check receipt")
|
|
746
1177
|
: null;
|
|
747
1178
|
const sequence = existingReceipt?.sequence
|
|
748
|
-
?? readChecks(executionRoot).length + 1;
|
|
1179
|
+
?? readChecks(root, executionRoot, runId).length + 1;
|
|
749
1180
|
const status = snapshot.status === "snapshot_passed"
|
|
750
1181
|
&& envelopeReceipt.formalEligible
|
|
751
1182
|
? "formal_check_passed"
|
|
752
1183
|
: "formal_check_failed";
|
|
753
|
-
const
|
|
754
|
-
|
|
1184
|
+
const failure = classifyFormalEnvelopeFailureV1({
|
|
1185
|
+
envelopeReceipt,
|
|
1186
|
+
snapshotStatus: snapshot.status,
|
|
1187
|
+
finalStatus: status,
|
|
1188
|
+
});
|
|
1189
|
+
const receiptBody = {
|
|
1190
|
+
schemaVersion: "OwlCodaRunKitFormalCheckV2",
|
|
755
1191
|
runId,
|
|
756
1192
|
checkId,
|
|
757
1193
|
sequence,
|
|
@@ -779,9 +1215,15 @@ async function recordFormalEnvelopeCheckWithinControlTransaction({
|
|
|
779
1215
|
envelopeReceiptPath: relativeToWorkspace(root, envelopeReceipt.receiptPath),
|
|
780
1216
|
envelopeReceiptSha256: envelopeReceipt.receiptSha256,
|
|
781
1217
|
envelopeFormalEligible: envelopeReceipt.formalEligible,
|
|
1218
|
+
failureCategory: failure.failureCategory,
|
|
1219
|
+
failureDetail: failure.failureDetail,
|
|
782
1220
|
finalized: false,
|
|
783
1221
|
authorizationGranted: false,
|
|
784
1222
|
};
|
|
1223
|
+
const receipt = {
|
|
1224
|
+
...receiptBody,
|
|
1225
|
+
formalCheckSha256: formalCheckHash(receiptBody),
|
|
1226
|
+
};
|
|
785
1227
|
const receiptResult = writeOrResumeExactJson(
|
|
786
1228
|
receiptPath,
|
|
787
1229
|
receipt,
|
|
@@ -812,7 +1254,7 @@ export function recordFormalEnvelopeCheckV1(options) {
|
|
|
812
1254
|
);
|
|
813
1255
|
}
|
|
814
1256
|
|
|
815
|
-
function finalizeFormalChecksWithinControlTransaction({
|
|
1257
|
+
export function finalizeFormalChecksWithinControlTransaction({
|
|
816
1258
|
workspaceRoot,
|
|
817
1259
|
runId,
|
|
818
1260
|
finalizeId,
|
|
@@ -822,7 +1264,7 @@ function finalizeFormalChecksWithinControlTransaction({
|
|
|
822
1264
|
const root = realpathSync(workspaceRoot);
|
|
823
1265
|
const { executionRoot, pinGate } = loadActiveExecution(root, runId);
|
|
824
1266
|
if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
|
|
825
|
-
const checks = readChecks(executionRoot);
|
|
1267
|
+
const checks = readChecks(root, executionRoot, runId);
|
|
826
1268
|
if (checks.length === 0) throw new Error("Formal finish requires at least one check.");
|
|
827
1269
|
const latest = checks.at(-1);
|
|
828
1270
|
const currentCandidate = verifySourceCandidateV2({
|
|
@@ -917,6 +1359,9 @@ export function resumeCompletedFormalFinishV1({
|
|
|
917
1359
|
const closeout = readRegularJson(closeoutPath, "Formal closeout receipt");
|
|
918
1360
|
const gate = validateCoreArtifact(closeout.artifact);
|
|
919
1361
|
const payload = closeout.artifact?.payload;
|
|
1362
|
+
const formalEvidenceBinding = closeout.artifact?.extensions?.[
|
|
1363
|
+
"dev.owlcoda.formal-evidence"
|
|
1364
|
+
] ?? null;
|
|
920
1365
|
if (
|
|
921
1366
|
!gate.valid
|
|
922
1367
|
|| closeout.acceptanceSha256 !== gate.acceptanceSha256
|
|
@@ -944,9 +1389,33 @@ export function resumeCompletedFormalFinishV1({
|
|
|
944
1389
|
closeoutArtifactSha256: closeout.artifactSha256,
|
|
945
1390
|
releasedLeaseIds: [],
|
|
946
1391
|
resumed: true,
|
|
1392
|
+
formalEvidenceBinding: null,
|
|
947
1393
|
authorizationGranted: false,
|
|
948
1394
|
};
|
|
949
1395
|
}
|
|
1396
|
+
if (
|
|
1397
|
+
closeout.artifact.core?.coreVersion === "0.19.2"
|
|
1398
|
+
&& (
|
|
1399
|
+
!hasExactKeys(formalEvidenceBinding, [
|
|
1400
|
+
"schemaVersion",
|
|
1401
|
+
"summaryPath",
|
|
1402
|
+
"summarySha256",
|
|
1403
|
+
"formalCheckCount",
|
|
1404
|
+
"supplementalEvidenceCount",
|
|
1405
|
+
"staleSupplementalEvidenceCount",
|
|
1406
|
+
"authorizationGranted",
|
|
1407
|
+
])
|
|
1408
|
+
|| formalEvidenceBinding.schemaVersion
|
|
1409
|
+
!== "OwlCodaRunKitFormalEvidenceCloseoutBindingV1"
|
|
1410
|
+
|| formalEvidenceBinding.summaryPath
|
|
1411
|
+
!== `.owlcoda/runkit/executions/${runId}`
|
|
1412
|
+
+ `/formal-evidence-summaries/${finalizeId}-evidence.json`
|
|
1413
|
+
|| !/^[a-f0-9]{64}$/u.test(formalEvidenceBinding.summarySha256)
|
|
1414
|
+
|| formalEvidenceBinding.authorizationGranted !== false
|
|
1415
|
+
)
|
|
1416
|
+
) {
|
|
1417
|
+
throw new Error("Existing closeout Formal evidence summary binding is invalid.");
|
|
1418
|
+
}
|
|
950
1419
|
const requestPath = path.join(
|
|
951
1420
|
executionRoot,
|
|
952
1421
|
"formal-finalize-requests",
|
|
@@ -1016,7 +1485,7 @@ export function resumeCompletedFormalFinishV1({
|
|
|
1016
1485
|
"Existing closeout Formal sourceArtifact bytes changed.",
|
|
1017
1486
|
);
|
|
1018
1487
|
}
|
|
1019
|
-
const checks = readChecks(executionRoot);
|
|
1488
|
+
const checks = readChecks(root, executionRoot, runId);
|
|
1020
1489
|
const selected = checks.filter((check) => (
|
|
1021
1490
|
check.status === "formal_check_passed"
|
|
1022
1491
|
&& check.sourceFingerprint === active.receipt.sourceFingerprint
|
|
@@ -1046,6 +1515,7 @@ export function resumeCompletedFormalFinishV1({
|
|
|
1046
1515
|
...payload.verification.releasedLeaseIds,
|
|
1047
1516
|
],
|
|
1048
1517
|
resumed: true,
|
|
1518
|
+
formalEvidenceBinding,
|
|
1049
1519
|
authorizationGranted: false,
|
|
1050
1520
|
};
|
|
1051
1521
|
}
|