intentdna 1.9.0 → 1.9.3
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +227 -87
- package/dist/cli/commands/run-lifecycle.d.ts +61 -11
- package/dist/cli/commands/run-lifecycle.js +184 -50
- package/dist/cli/commands/run-observer.d.ts +15 -0
- package/dist/cli/commands/run-observer.js +210 -0
- package/dist/cli/commands/run.d.ts +16 -20
- package/dist/cli/commands/run.js +461 -659
- package/dist/cli/commands/sync.js +16 -12
- package/dist/cli/index.js +14 -5
- package/dist/compiler/compile.d.ts +1 -0
- package/dist/compiler/compile.js +1 -1
- package/dist/compiler/controller.d.ts +16 -0
- package/dist/compiler/controller.js +693 -0
- package/dist/compiler/input-resolver.d.ts +2 -0
- package/dist/compiler/input-resolver.js +22 -6
- package/dist/hooks/cli.d.ts +45 -0
- package/dist/hooks/cli.js +263 -31
- package/dist/hooks/host-event.d.ts +57 -0
- package/dist/hooks/host-event.js +187 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/protocol.d.ts +7 -0
- package/dist/hooks/schema.d.ts +1 -0
- package/dist/hooks/schema.js +89 -1
- package/dist/hooks/state.d.ts +23 -1
- package/dist/hooks/state.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/tools-run.d.ts +4 -0
- package/dist/mcp/tools-run.js +419 -0
- package/dist/mcp/tools-state.d.ts +1 -1
- package/dist/mcp/tools-state.js +13 -241
- package/dist/runtime/artifact-store.d.ts +146 -0
- package/dist/runtime/artifact-store.js +1436 -0
- package/dist/runtime/canonical-attempt-outcome.d.ts +12 -0
- package/dist/runtime/canonical-attempt-outcome.js +195 -0
- package/dist/runtime/canonical-json.d.ts +10 -0
- package/dist/runtime/canonical-json.js +105 -0
- package/dist/runtime/canonical-run-application.d.ts +93 -0
- package/dist/runtime/canonical-run-application.js +229 -0
- package/dist/runtime/canonical-run-service.d.ts +454 -0
- package/dist/runtime/canonical-run-service.js +4760 -0
- package/dist/runtime/canonical-runtime-composition.d.ts +22 -0
- package/dist/runtime/canonical-runtime-composition.js +34 -0
- package/dist/runtime/canonical-runtime-projection.d.ts +3 -0
- package/dist/runtime/canonical-runtime-projection.js +4 -0
- package/dist/runtime/canonical-target-compiler.d.ts +46 -0
- package/dist/runtime/canonical-target-compiler.js +514 -0
- package/dist/runtime/claude-agent-identity.d.ts +2 -0
- package/dist/runtime/claude-agent-identity.js +21 -0
- package/dist/runtime/executable-run-plan.d.ts +328 -0
- package/dist/runtime/executable-run-plan.js +1485 -0
- package/dist/runtime/execution-authority.d.ts +83 -0
- package/dist/runtime/execution-authority.js +98 -0
- package/dist/runtime/handoff-resolver.js +4 -1
- package/dist/runtime/harness-pull-adapter.d.ts +146 -0
- package/dist/runtime/harness-pull-adapter.js +315 -0
- package/dist/runtime/index.d.ts +39 -14
- package/dist/runtime/index.js +29 -7
- package/dist/runtime/local-execution-authority.d.ts +194 -0
- package/dist/runtime/local-execution-authority.js +2897 -0
- package/dist/runtime/local-execution-reconciliation.d.ts +20 -0
- package/dist/runtime/local-execution-reconciliation.js +107 -0
- package/dist/runtime/local-execution-supervisor-script.d.ts +7 -0
- package/dist/runtime/local-execution-supervisor-script.js +793 -0
- package/dist/runtime/local-provider-sandbox.d.ts +42 -0
- package/dist/runtime/local-provider-sandbox.js +154 -0
- package/dist/runtime/local-verifier-execution.d.ts +24 -0
- package/dist/runtime/local-verifier-execution.js +290 -0
- package/dist/runtime/local-windows-execution-supervisor-script.d.ts +6 -0
- package/dist/runtime/local-windows-execution-supervisor-script.js +788 -0
- package/dist/runtime/plan-store.d.ts +30 -0
- package/dist/runtime/plan-store.js +231 -0
- package/dist/runtime/process-tree.d.ts +9 -0
- package/dist/runtime/process-tree.js +97 -24
- package/dist/runtime/providers/codex.js +2 -2
- package/dist/runtime/push-driver.d.ts +184 -0
- package/dist/runtime/push-driver.js +1002 -0
- package/dist/runtime/result-store.d.ts +34 -3
- package/dist/runtime/result-store.js +1073 -2
- package/dist/runtime/run-binding.d.ts +68 -0
- package/dist/runtime/run-binding.js +278 -0
- package/dist/runtime/run-contracts.d.ts +575 -0
- package/dist/runtime/run-contracts.js +58 -7
- package/dist/runtime/run-controller.d.ts +1 -6
- package/dist/runtime/run-controller.js +0 -41
- package/dist/runtime/run-store.d.ts +85 -7
- package/dist/runtime/run-store.js +2528 -186
- package/dist/runtime/skill-adapter.d.ts +18 -7
- package/dist/runtime/skill-adapter.js +100 -742
- package/dist/runtime/structured-output-validator.d.ts +44 -0
- package/dist/runtime/structured-output-validator.js +171 -0
- package/dist/runtime/verifier-command-binding.d.ts +22 -0
- package/dist/runtime/verifier-command-binding.js +162 -0
- package/dist/runtime/verifier.d.ts +46 -6
- package/dist/runtime/verifier.js +355 -53
- package/dist/runtime/windows-job-keeper.d.ts +47 -0
- package/dist/runtime/windows-job-keeper.js +231 -0
- package/dist/runtime/worker-executor.d.ts +17 -1
- package/dist/runtime/worker-executor.js +26 -5
- package/dist/runtime/workflow-plan-adapter.d.ts +19 -0
- package/dist/runtime/workflow-plan-adapter.js +502 -6
- package/dist/runtime/workflow-runtime-manifest.d.ts +1 -0
- package/dist/runtime/workflow-runtime-manifest.js +5 -0
- package/dist/runtime/workspace-isolation.d.ts +29 -2
- package/dist/runtime/workspace-isolation.js +488 -11
- package/dist/runtime/workspace-observation.d.ts +44 -0
- package/dist/runtime/workspace-observation.js +216 -0
- package/dist/schema/controller-registry.d.ts +0 -7
- package/dist/schema/controller-registry.js +0 -8
- package/dist/schema/types.d.ts +84 -10
- package/dist/schema/types.js +2 -0
- package/dist/schema/validate.js +151 -1
- package/dist/schema/validators/controllers.d.ts +1 -1
- package/dist/schema/validators/controllers.js +126 -41
- package/dist/schema/workflow-authoring-contract.js +2 -0
- package/dist/schema/yaml-parser.js +1 -1
- package/dist/templates/flutter-rewrite-new.dna.yaml +1 -0
- package/dist/templates/flutter-rewrite.dna.yaml +87 -60
- package/dist/templates/safe-refactoring.dna.yaml +1 -0
- package/native/windows-job-keeper/README.md +80 -0
- package/native/windows-job-keeper/bin/aarch64/intentdna-windows-job-keeper.exe +0 -0
- package/native/windows-job-keeper/bin/x86_64/intentdna-windows-job-keeper.exe +0 -0
- package/native/windows-job-keeper/keeper.c +979 -0
- package/native/windows-job-keeper/manifest.json +33 -0
- package/package.json +6 -2
- package/scripts/build-windows-job-keeper.mjs +172 -0
- package/scripts/verify-windows-job-keeper.mjs +184 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ActivationId, AttemptExecutor, AttemptId, CanonicalAttemptOutcome, CanonicalResultDigest, CanonicalWorkerStopReceipt, CanonicalWorkerStopReceiptPayload, CanonicalWorkerNonlaunchAttestation, CanonicalWorkerNonlaunchAttestationPayload, CanonicalWorkerAlreadyStoppedEvidence, CanonicalWorkerAlreadyStoppedEvidencePayload, RunId, StepId } from "./run-contracts.js";
|
|
2
|
+
export interface AttemptExecutionAuthorityRequest {
|
|
3
|
+
readonly run_id: RunId;
|
|
4
|
+
readonly step_id: StepId;
|
|
5
|
+
readonly activation_id: ActivationId;
|
|
6
|
+
readonly attempt_id: AttemptId;
|
|
7
|
+
readonly claim_epoch: number;
|
|
8
|
+
readonly executor: Extract<AttemptExecutor, {
|
|
9
|
+
kind: "worker";
|
|
10
|
+
}>;
|
|
11
|
+
readonly purpose: "finalize_result" | "reconcile_published_result";
|
|
12
|
+
readonly reported_execution: {
|
|
13
|
+
readonly started_at: string;
|
|
14
|
+
readonly completed_at: string;
|
|
15
|
+
readonly outcome: CanonicalAttemptOutcome;
|
|
16
|
+
};
|
|
17
|
+
readonly expected_receipt: CanonicalWorkerStopReceipt | null;
|
|
18
|
+
}
|
|
19
|
+
export type StopExecutionPurpose = "cancel" | "execution_deadline" | "peer_terminal";
|
|
20
|
+
export interface StopExecutionRequest {
|
|
21
|
+
readonly run_id: RunId;
|
|
22
|
+
readonly step_id: StepId;
|
|
23
|
+
readonly activation_id: ActivationId;
|
|
24
|
+
readonly attempt_id: AttemptId;
|
|
25
|
+
readonly claim_epoch: number;
|
|
26
|
+
readonly executor: Extract<AttemptExecutor, {
|
|
27
|
+
kind: "worker";
|
|
28
|
+
}>;
|
|
29
|
+
readonly purpose: StopExecutionPurpose;
|
|
30
|
+
readonly requested_at: string;
|
|
31
|
+
readonly started_at: string;
|
|
32
|
+
readonly requested_outcome: CanonicalAttemptOutcome;
|
|
33
|
+
readonly stop_idempotency_key: CanonicalResultDigest;
|
|
34
|
+
readonly expected_receipt: CanonicalWorkerStopReceipt | null;
|
|
35
|
+
}
|
|
36
|
+
export interface StoppedExecutionAuthority {
|
|
37
|
+
readonly stop_receipt: CanonicalWorkerStopReceipt;
|
|
38
|
+
readonly authority_instance_id: string;
|
|
39
|
+
readonly fencing_epoch: number;
|
|
40
|
+
}
|
|
41
|
+
export type StopExecutionResolution = {
|
|
42
|
+
readonly kind: "stopped_by_request";
|
|
43
|
+
readonly authority: StoppedExecutionAuthority;
|
|
44
|
+
} | {
|
|
45
|
+
readonly kind: "already_stopped";
|
|
46
|
+
readonly drain_evidence: CanonicalWorkerAlreadyStoppedEvidence;
|
|
47
|
+
} | {
|
|
48
|
+
readonly kind: "never_launched";
|
|
49
|
+
readonly nonlaunch_attestation: CanonicalWorkerNonlaunchAttestation;
|
|
50
|
+
};
|
|
51
|
+
export interface ExecutionRecoveryProbeRequest {
|
|
52
|
+
readonly run_id: RunId;
|
|
53
|
+
readonly step_id: StepId;
|
|
54
|
+
readonly activation_id: ActivationId;
|
|
55
|
+
readonly attempt_id: AttemptId;
|
|
56
|
+
readonly execution_claim_epoch: number;
|
|
57
|
+
readonly executor: Extract<AttemptExecutor, {
|
|
58
|
+
kind: "worker";
|
|
59
|
+
}>;
|
|
60
|
+
readonly started_at: string;
|
|
61
|
+
}
|
|
62
|
+
export interface ExecutionRecoveryState {
|
|
63
|
+
readonly raw_completion_durable: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface NeverLaunchedAttestationRequest extends ExecutionRecoveryProbeRequest {
|
|
66
|
+
readonly failure_idempotency_key: CanonicalResultDigest;
|
|
67
|
+
readonly requested_at: string;
|
|
68
|
+
}
|
|
69
|
+
export interface AttemptExecutionAuthorityPort {
|
|
70
|
+
withStoppedExecution<T>(request: AttemptExecutionAuthorityRequest, operation: (authority: StoppedExecutionAuthority) => Promise<T>): Promise<T>;
|
|
71
|
+
requestStop?(request: StopExecutionRequest): Promise<StopExecutionResolution>;
|
|
72
|
+
probeRecovery?(request: ExecutionRecoveryProbeRequest): Promise<ExecutionRecoveryState>;
|
|
73
|
+
attestNeverLaunched?(request: NeverLaunchedAttestationRequest): Promise<CanonicalWorkerNonlaunchAttestation>;
|
|
74
|
+
}
|
|
75
|
+
export declare function workerNonlaunchAttestationDigest(payload: CanonicalWorkerNonlaunchAttestationPayload): CanonicalWorkerNonlaunchAttestation["attestation_digest"];
|
|
76
|
+
export declare function workerNonlaunchAttestationMatches(attestation: CanonicalWorkerNonlaunchAttestation, request: NeverLaunchedAttestationRequest): boolean;
|
|
77
|
+
export declare function workerStopReceiptDigest(payload: CanonicalWorkerStopReceiptPayload): CanonicalWorkerStopReceipt["receipt_digest"];
|
|
78
|
+
export declare function workerAlreadyStoppedEvidenceDigest(payload: CanonicalWorkerAlreadyStoppedEvidencePayload): CanonicalWorkerAlreadyStoppedEvidence["evidence_digest"];
|
|
79
|
+
export declare function createWorkerAlreadyStoppedEvidence(payload: CanonicalWorkerAlreadyStoppedEvidencePayload): CanonicalWorkerAlreadyStoppedEvidence;
|
|
80
|
+
export declare function workerAlreadyStoppedEvidenceMatchesStop(evidence: CanonicalWorkerAlreadyStoppedEvidence, request: StopExecutionRequest): boolean;
|
|
81
|
+
export declare function createWorkerStopReceipt(payload: CanonicalWorkerStopReceiptPayload): CanonicalWorkerStopReceipt;
|
|
82
|
+
export declare function workerStopReceiptMatchesExecution(receipt: CanonicalWorkerStopReceipt, request: AttemptExecutionAuthorityRequest): boolean;
|
|
83
|
+
export declare function workerStopReceiptMatchesStop(receipt: CanonicalWorkerStopReceipt, request: StopExecutionRequest): boolean;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { canonicalizeJson } from "./canonical-json.js";
|
|
3
|
+
export function workerNonlaunchAttestationDigest(payload) {
|
|
4
|
+
return `sha256:${createHash("sha256")
|
|
5
|
+
.update(canonicalizeJson(payload), "utf8")
|
|
6
|
+
.digest("hex")}`;
|
|
7
|
+
}
|
|
8
|
+
export function workerNonlaunchAttestationMatches(attestation, request) {
|
|
9
|
+
const payload = attestation.payload;
|
|
10
|
+
return attestation.attestation_digest === workerNonlaunchAttestationDigest(payload)
|
|
11
|
+
&& payload.run_id === request.run_id
|
|
12
|
+
&& payload.step_id === request.step_id
|
|
13
|
+
&& payload.activation_id === request.activation_id
|
|
14
|
+
&& payload.attempt_id === request.attempt_id
|
|
15
|
+
&& payload.claim_epoch === request.execution_claim_epoch
|
|
16
|
+
&& payload.worker_session_id === request.executor.worker_session_id
|
|
17
|
+
&& payload.started_at === request.started_at
|
|
18
|
+
&& payload.failure_idempotency_key === request.failure_idempotency_key
|
|
19
|
+
&& payload.launch_state === "never_launched"
|
|
20
|
+
&& payload.fencing_epoch > 0;
|
|
21
|
+
}
|
|
22
|
+
export function workerStopReceiptDigest(payload) {
|
|
23
|
+
return `sha256:${createHash("sha256")
|
|
24
|
+
.update(canonicalizeJson(payload), "utf8")
|
|
25
|
+
.digest("hex")}`;
|
|
26
|
+
}
|
|
27
|
+
export function workerAlreadyStoppedEvidenceDigest(payload) {
|
|
28
|
+
return `sha256:${createHash("sha256")
|
|
29
|
+
.update(canonicalizeJson(payload), "utf8")
|
|
30
|
+
.digest("hex")}`;
|
|
31
|
+
}
|
|
32
|
+
export function createWorkerAlreadyStoppedEvidence(payload) {
|
|
33
|
+
return {
|
|
34
|
+
evidence_digest: workerAlreadyStoppedEvidenceDigest(payload),
|
|
35
|
+
payload,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function workerAlreadyStoppedEvidenceMatchesStop(evidence, request) {
|
|
39
|
+
const payload = evidence.payload;
|
|
40
|
+
return evidence.evidence_digest === workerAlreadyStoppedEvidenceDigest(payload)
|
|
41
|
+
&& payload.run_id === request.run_id
|
|
42
|
+
&& payload.step_id === request.step_id
|
|
43
|
+
&& payload.activation_id === request.activation_id
|
|
44
|
+
&& payload.attempt_id === request.attempt_id
|
|
45
|
+
&& payload.claim_epoch === request.claim_epoch
|
|
46
|
+
&& payload.worker_session_id === request.executor.worker_session_id
|
|
47
|
+
&& payload.started_at === request.started_at
|
|
48
|
+
&& payload.completed_at >= payload.started_at
|
|
49
|
+
&& payload.process_tree_drained === true
|
|
50
|
+
&& payload.stop_idempotency_key === request.stop_idempotency_key
|
|
51
|
+
&& payload.stop_requested_at === request.requested_at
|
|
52
|
+
&& payload.stop_purpose === request.purpose
|
|
53
|
+
&& canonicalizeJson(payload.stop_requested_outcome) === canonicalizeJson(request.requested_outcome)
|
|
54
|
+
&& payload.execution_instance_id.length > 0
|
|
55
|
+
&& (payload.authority_kind === "local_process" || payload.authority_kind === "host_attested")
|
|
56
|
+
&& payload.authority_instance_id.length > 0
|
|
57
|
+
&& Number.isSafeInteger(payload.fencing_epoch)
|
|
58
|
+
&& payload.fencing_epoch > 0
|
|
59
|
+
&& /^sha256:[0-9a-f]{64}$/.test(payload.source_evidence_digest);
|
|
60
|
+
}
|
|
61
|
+
export function createWorkerStopReceipt(payload) {
|
|
62
|
+
return {
|
|
63
|
+
receipt_digest: workerStopReceiptDigest(payload),
|
|
64
|
+
payload,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function workerStopReceiptMatchesExecution(receipt, request) {
|
|
68
|
+
const payload = receipt.payload;
|
|
69
|
+
return receipt.receipt_digest === workerStopReceiptDigest(payload)
|
|
70
|
+
&& payload.run_id === request.run_id
|
|
71
|
+
&& payload.step_id === request.step_id
|
|
72
|
+
&& payload.activation_id === request.activation_id
|
|
73
|
+
&& payload.attempt_id === request.attempt_id
|
|
74
|
+
&& payload.claim_epoch === request.claim_epoch
|
|
75
|
+
&& payload.worker_session_id === request.executor.worker_session_id
|
|
76
|
+
&& payload.started_at === request.reported_execution.started_at
|
|
77
|
+
&& payload.stopped_at === request.reported_execution.completed_at
|
|
78
|
+
&& canonicalizeJson(payload.terminal_outcome)
|
|
79
|
+
=== canonicalizeJson(request.reported_execution.outcome)
|
|
80
|
+
&& payload.process_tree_drained === true;
|
|
81
|
+
}
|
|
82
|
+
export function workerStopReceiptMatchesStop(receipt, request) {
|
|
83
|
+
const payload = receipt.payload;
|
|
84
|
+
return receipt.receipt_digest === workerStopReceiptDigest(payload)
|
|
85
|
+
&& payload.run_id === request.run_id
|
|
86
|
+
&& payload.step_id === request.step_id
|
|
87
|
+
&& payload.activation_id === request.activation_id
|
|
88
|
+
&& payload.attempt_id === request.attempt_id
|
|
89
|
+
&& payload.claim_epoch === request.claim_epoch
|
|
90
|
+
&& payload.worker_session_id === request.executor.worker_session_id
|
|
91
|
+
&& payload.started_at === request.started_at
|
|
92
|
+
&& payload.stopped_at >= request.requested_at
|
|
93
|
+
&& canonicalizeJson(payload.terminal_outcome)
|
|
94
|
+
=== canonicalizeJson(request.requested_outcome)
|
|
95
|
+
&& (request.expected_receipt === null
|
|
96
|
+
|| canonicalizeJson(receipt) === canonicalizeJson(request.expected_receipt))
|
|
97
|
+
&& payload.process_tree_drained === true;
|
|
98
|
+
}
|
|
@@ -76,7 +76,10 @@ export class HandoffResolver {
|
|
|
76
76
|
description: request.description,
|
|
77
77
|
mode: "reference",
|
|
78
78
|
source: request.source,
|
|
79
|
-
reference:
|
|
79
|
+
reference: {
|
|
80
|
+
...output.reference,
|
|
81
|
+
artifact_id: null,
|
|
82
|
+
},
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
if (request.mode === "quote") {
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { CanonicalRunApplication, type CompiledCanonicalTarget, type StartCanonicalTargetRequest } from "./canonical-run-application.js";
|
|
2
|
+
import { type AcquireAttemptResponse, type AttemptExecutionSubmission, type AttemptView, type HeartbeatRequest, type LeaseView, type RunView, type StartRunResponse, type SubmitResponse } from "./canonical-run-service.js";
|
|
3
|
+
import type { DriverCapabilities, ExecutableRunPlanPayload } from "./executable-run-plan.js";
|
|
4
|
+
import type { CompiledIRFile } from "./plugin-adapter.js";
|
|
5
|
+
import type { CanonicalCallerAttestationPayload, CanonicalEvidenceRef, CanonicalAttemptRecord, CanonicalResultDigest, ClaimToken, JsonValue, RunId, WorkerSessionId } from "./run-contracts.js";
|
|
6
|
+
export declare const HARNESS_RUN_METADATA_SCHEMA_VERSION = "intentdna.harness_run_metadata.v1";
|
|
7
|
+
export declare const HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION: "intentdna.harness_caller_attestation.v1";
|
|
8
|
+
export declare const HARNESS_SUBMISSION_MODE_VALUES: readonly ["relayed_submit", "attested_independent_submit"];
|
|
9
|
+
export type HarnessSubmissionMode = typeof HARNESS_SUBMISSION_MODE_VALUES[number];
|
|
10
|
+
export type HarnessPullAdapterErrorCode = "invalid_configuration" | "invalid_request" | "invalid_service_response" | "unsupported";
|
|
11
|
+
export declare class HarnessPullAdapterError extends Error {
|
|
12
|
+
readonly code: HarnessPullAdapterErrorCode;
|
|
13
|
+
constructor(code: HarnessPullAdapterErrorCode, message: string, options?: ErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
export interface HarnessPullCapabilities {
|
|
16
|
+
readonly driver: Readonly<DriverCapabilities>;
|
|
17
|
+
readonly submission_modes: readonly HarnessSubmissionMode[];
|
|
18
|
+
readonly stopped_execution_authority: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface HarnessRunMetadata {
|
|
21
|
+
readonly schema_version: typeof HARNESS_RUN_METADATA_SCHEMA_VERSION;
|
|
22
|
+
readonly transport: "harness_pull";
|
|
23
|
+
readonly project_directory: string;
|
|
24
|
+
readonly target: StartCanonicalTargetRequest["target"];
|
|
25
|
+
readonly compiled_ir: CompiledIRFile | null;
|
|
26
|
+
readonly requested_metadata: JsonValue | null;
|
|
27
|
+
}
|
|
28
|
+
export type HarnessCallerAttestationPayload = CanonicalCallerAttestationPayload;
|
|
29
|
+
export interface HarnessCallerAttestation {
|
|
30
|
+
readonly attestation_ref: string;
|
|
31
|
+
readonly attestation_digest: CanonicalResultDigest;
|
|
32
|
+
readonly payload: HarnessCallerAttestationPayload;
|
|
33
|
+
}
|
|
34
|
+
export interface HarnessCallerAttestationRequest {
|
|
35
|
+
readonly run: RunView;
|
|
36
|
+
readonly submission: {
|
|
37
|
+
readonly attempt: CanonicalAttemptRecord;
|
|
38
|
+
readonly claim_epoch: number;
|
|
39
|
+
readonly submission_key_digest: CanonicalResultDigest;
|
|
40
|
+
readonly execution_digest: CanonicalResultDigest;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* This port is a composition-root trust anchor. It must derive the current
|
|
45
|
+
* caller from host-authenticated context. The adapter supplies only durable
|
|
46
|
+
* submission facts; tool arguments are never caller attestation.
|
|
47
|
+
*/
|
|
48
|
+
export interface HarnessCallerAttestationAuthority {
|
|
49
|
+
readonly authority_id: string;
|
|
50
|
+
attest(request: HarnessCallerAttestationRequest): Promise<HarnessCallerAttestation>;
|
|
51
|
+
}
|
|
52
|
+
export interface HarnessAttemptProjectionContext {
|
|
53
|
+
readonly run: RunView;
|
|
54
|
+
readonly attached: AttemptView;
|
|
55
|
+
readonly lease_token: ClaimToken;
|
|
56
|
+
readonly owner_id: string;
|
|
57
|
+
readonly worker_session_id: WorkerSessionId;
|
|
58
|
+
readonly submission_mode: HarnessSubmissionMode;
|
|
59
|
+
readonly metadata: HarnessRunMetadata | null;
|
|
60
|
+
}
|
|
61
|
+
export interface HarnessPullService {
|
|
62
|
+
start(request: {
|
|
63
|
+
readonly plan_payload: ExecutableRunPlanPayload;
|
|
64
|
+
readonly run_binding: CompiledCanonicalTarget["run_binding"];
|
|
65
|
+
readonly metadata?: JsonValue;
|
|
66
|
+
readonly run_id?: RunId;
|
|
67
|
+
}): Promise<StartRunResponse>;
|
|
68
|
+
inspect(runId: RunId): Promise<RunView>;
|
|
69
|
+
resume(runId: RunId): Promise<RunView>;
|
|
70
|
+
acquireAttempt(request: {
|
|
71
|
+
readonly run_id: RunId;
|
|
72
|
+
readonly driver_id: string;
|
|
73
|
+
readonly recover_running?: boolean;
|
|
74
|
+
}): Promise<AcquireAttemptResponse>;
|
|
75
|
+
attachAttempt(request: {
|
|
76
|
+
readonly lease_token: ClaimToken;
|
|
77
|
+
readonly owner_id: string;
|
|
78
|
+
readonly worker_identity: string;
|
|
79
|
+
readonly capabilities: Partial<DriverCapabilities>;
|
|
80
|
+
}): Promise<AttemptView>;
|
|
81
|
+
heartbeat(request: HeartbeatRequest): Promise<LeaseView>;
|
|
82
|
+
submitAttempt(request: {
|
|
83
|
+
readonly lease_token: ClaimToken;
|
|
84
|
+
readonly owner_id: string;
|
|
85
|
+
readonly submission_key: string;
|
|
86
|
+
readonly execution: AttemptExecutionSubmission;
|
|
87
|
+
readonly evidence_refs?: readonly CanonicalEvidenceRef[];
|
|
88
|
+
}): Promise<SubmitResponse>;
|
|
89
|
+
cancel(runId: RunId, reason?: string | null): Promise<RunView>;
|
|
90
|
+
}
|
|
91
|
+
export interface HarnessAttemptAttachRequest {
|
|
92
|
+
readonly run_id: RunId;
|
|
93
|
+
readonly attempt_id: string;
|
|
94
|
+
readonly lease_token: ClaimToken;
|
|
95
|
+
readonly owner_id: string;
|
|
96
|
+
readonly worker_session_id: WorkerSessionId;
|
|
97
|
+
readonly submission_mode: HarnessSubmissionMode;
|
|
98
|
+
}
|
|
99
|
+
export interface HarnessAttemptSubmitRequest {
|
|
100
|
+
readonly run_id: RunId;
|
|
101
|
+
readonly attempt_id: string;
|
|
102
|
+
readonly lease_token: ClaimToken;
|
|
103
|
+
readonly owner_id: string;
|
|
104
|
+
readonly submission_key: string;
|
|
105
|
+
readonly submission_mode: HarnessSubmissionMode;
|
|
106
|
+
readonly execution: AttemptExecutionSubmission;
|
|
107
|
+
readonly evidence_refs?: readonly CanonicalEvidenceRef[];
|
|
108
|
+
}
|
|
109
|
+
export interface HarnessPullAdapterOptions {
|
|
110
|
+
readonly service: HarnessPullService;
|
|
111
|
+
readonly application?: CanonicalRunApplication<StartRunResponse>;
|
|
112
|
+
readonly capabilities: HarnessPullCapabilities;
|
|
113
|
+
readonly caller_attestation_authority?: HarnessCallerAttestationAuthority;
|
|
114
|
+
readonly attempt_projection_sink?: (context: HarnessAttemptProjectionContext) => Promise<void> | void;
|
|
115
|
+
readonly validate_worker_session_id?: (workerSessionId: WorkerSessionId) => void;
|
|
116
|
+
readonly driver_id?: string;
|
|
117
|
+
}
|
|
118
|
+
export declare function parseHarnessRunMetadata(value: JsonValue): HarnessRunMetadata | null;
|
|
119
|
+
export declare function harnessCallerAttestationDigest(payload: HarnessCallerAttestationPayload): CanonicalResultDigest;
|
|
120
|
+
export declare class HarnessPullAdapter {
|
|
121
|
+
readonly capabilities: HarnessPullCapabilities;
|
|
122
|
+
private readonly service;
|
|
123
|
+
private readonly application;
|
|
124
|
+
private readonly callerAttestationAuthority;
|
|
125
|
+
private readonly attemptProjectionSink;
|
|
126
|
+
private readonly validateWorkerSessionId;
|
|
127
|
+
private readonly driverId;
|
|
128
|
+
constructor(options: HarnessPullAdapterOptions);
|
|
129
|
+
start(request: StartCanonicalTargetRequest): Promise<StartRunResponse>;
|
|
130
|
+
startCompiled(request: {
|
|
131
|
+
readonly compiled: CompiledCanonicalTarget;
|
|
132
|
+
readonly project_directory: string;
|
|
133
|
+
readonly target: StartCanonicalTargetRequest["target"];
|
|
134
|
+
readonly metadata?: JsonValue;
|
|
135
|
+
readonly run_id?: RunId;
|
|
136
|
+
}): Promise<StartRunResponse>;
|
|
137
|
+
next(runId: RunId): Promise<AcquireAttemptResponse>;
|
|
138
|
+
attach(request: HarnessAttemptAttachRequest): Promise<AttemptView>;
|
|
139
|
+
heartbeat(request: HeartbeatRequest): Promise<LeaseView>;
|
|
140
|
+
submit(request: HarnessAttemptSubmitRequest): Promise<SubmitResponse>;
|
|
141
|
+
status(runId: RunId): Promise<RunView>;
|
|
142
|
+
cancel(runId: RunId, reason?: string | null): Promise<RunView>;
|
|
143
|
+
private requireAttempt;
|
|
144
|
+
private assertSubmissionMode;
|
|
145
|
+
private attestSubmission;
|
|
146
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { CanonicalRunApplication, } from "./canonical-run-application.js";
|
|
3
|
+
import { canonicalizeJson } from "./canonical-json.js";
|
|
4
|
+
import { durableCanonicalRuntimeProjection } from "./canonical-runtime-projection.js";
|
|
5
|
+
import { CALLER_ATTESTATION_SCHEMA_VERSION } from "./run-contracts.js";
|
|
6
|
+
export const HARNESS_RUN_METADATA_SCHEMA_VERSION = "intentdna.harness_run_metadata.v1";
|
|
7
|
+
export const HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION = CALLER_ATTESTATION_SCHEMA_VERSION;
|
|
8
|
+
export const HARNESS_SUBMISSION_MODE_VALUES = [
|
|
9
|
+
"relayed_submit",
|
|
10
|
+
"attested_independent_submit",
|
|
11
|
+
];
|
|
12
|
+
export class HarnessPullAdapterError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(code, message, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.name = "HarnessPullAdapterError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function digest(value) {
|
|
21
|
+
return `sha256:${createHash("sha256")
|
|
22
|
+
.update(canonicalizeJson(value), "utf8")
|
|
23
|
+
.digest("hex")}`;
|
|
24
|
+
}
|
|
25
|
+
function requireText(value, label) {
|
|
26
|
+
if (!value.trim()) {
|
|
27
|
+
throw new HarnessPullAdapterError("invalid_request", `${label} must be non-empty`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function canonicalMetadata(compiled, request) {
|
|
31
|
+
const metadata = {
|
|
32
|
+
schema_version: HARNESS_RUN_METADATA_SCHEMA_VERSION,
|
|
33
|
+
transport: "harness_pull",
|
|
34
|
+
project_directory: request.environment.project_root,
|
|
35
|
+
target: request.target,
|
|
36
|
+
compiled_ir: compiled.projection === null
|
|
37
|
+
? null
|
|
38
|
+
: durableCanonicalRuntimeProjection(compiled.projection),
|
|
39
|
+
requested_metadata: request.metadata ?? null,
|
|
40
|
+
};
|
|
41
|
+
return JSON.parse(canonicalizeJson(metadata));
|
|
42
|
+
}
|
|
43
|
+
export function parseHarnessRunMetadata(value) {
|
|
44
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
45
|
+
return null;
|
|
46
|
+
const record = value;
|
|
47
|
+
if (record.schema_version !== HARNESS_RUN_METADATA_SCHEMA_VERSION
|
|
48
|
+
|| record.transport !== "harness_pull"
|
|
49
|
+
|| typeof record.project_directory !== "string"
|
|
50
|
+
|| record.target === null
|
|
51
|
+
|| typeof record.target !== "object") {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
export function harnessCallerAttestationDigest(payload) {
|
|
57
|
+
return digest(payload);
|
|
58
|
+
}
|
|
59
|
+
function validateCapabilities(capabilities, authority, projectionSink) {
|
|
60
|
+
const modes = new Set(capabilities.submission_modes);
|
|
61
|
+
if (capabilities.submission_modes.length !== modes.size
|
|
62
|
+
|| capabilities.submission_modes.some((mode) => !HARNESS_SUBMISSION_MODE_VALUES.includes(mode))) {
|
|
63
|
+
throw new HarnessPullAdapterError("invalid_configuration", "harness submission modes are invalid");
|
|
64
|
+
}
|
|
65
|
+
if (modes.has("relayed_submit")
|
|
66
|
+
&& capabilities.driver.direct_structured_submission !== true) {
|
|
67
|
+
throw new HarnessPullAdapterError("invalid_configuration", "relayed_submit requires direct_structured_submission");
|
|
68
|
+
}
|
|
69
|
+
if (modes.has("attested_independent_submit")
|
|
70
|
+
!== (capabilities.driver.caller_attestation === true)
|
|
71
|
+
|| capabilities.driver.caller_attestation === true && authority === undefined) {
|
|
72
|
+
throw new HarnessPullAdapterError("invalid_configuration", "attested_independent_submit requires a trusted caller attestation authority");
|
|
73
|
+
}
|
|
74
|
+
if (capabilities.driver.hook_identity === true && projectionSink === undefined) {
|
|
75
|
+
throw new HarnessPullAdapterError("invalid_configuration", "hook_identity requires an attempt projection sink");
|
|
76
|
+
}
|
|
77
|
+
if (capabilities.driver.cancellation === true
|
|
78
|
+
&& capabilities.stopped_execution_authority !== true) {
|
|
79
|
+
throw new HarnessPullAdapterError("invalid_configuration", "cancellation requires stopped-execution authority");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function assertRequiredCapabilities(plan, capabilities) {
|
|
83
|
+
for (const [name, required] of Object.entries(plan.required_capabilities)) {
|
|
84
|
+
if (required && capabilities[name] !== true) {
|
|
85
|
+
throw new HarnessPullAdapterError("unsupported", `harness capability ${name} is required`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function sameJson(left, right) {
|
|
90
|
+
try {
|
|
91
|
+
return canonicalizeJson(left) === canonicalizeJson(right);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export class HarnessPullAdapter {
|
|
98
|
+
capabilities;
|
|
99
|
+
service;
|
|
100
|
+
application;
|
|
101
|
+
callerAttestationAuthority;
|
|
102
|
+
attemptProjectionSink;
|
|
103
|
+
validateWorkerSessionId;
|
|
104
|
+
driverId;
|
|
105
|
+
constructor(options) {
|
|
106
|
+
validateCapabilities(options.capabilities, options.caller_attestation_authority, options.attempt_projection_sink);
|
|
107
|
+
this.service = options.service;
|
|
108
|
+
this.application = options.application
|
|
109
|
+
?? new CanonicalRunApplication({ starter: options.service });
|
|
110
|
+
this.capabilities = Object.freeze({
|
|
111
|
+
driver: Object.freeze({ ...options.capabilities.driver }),
|
|
112
|
+
submission_modes: Object.freeze([...options.capabilities.submission_modes]),
|
|
113
|
+
stopped_execution_authority: options.capabilities.stopped_execution_authority,
|
|
114
|
+
});
|
|
115
|
+
this.callerAttestationAuthority = options.caller_attestation_authority;
|
|
116
|
+
this.attemptProjectionSink = options.attempt_projection_sink;
|
|
117
|
+
this.validateWorkerSessionId = options.validate_worker_session_id;
|
|
118
|
+
this.driverId = options.driver_id ?? `harness-pull:${process.pid}:${randomUUID()}`;
|
|
119
|
+
requireText(this.driverId, "driver_id");
|
|
120
|
+
}
|
|
121
|
+
async start(request) {
|
|
122
|
+
const compiled = await this.application.compileTarget(request);
|
|
123
|
+
assertRequiredCapabilities(compiled.plan_payload, this.capabilities.driver);
|
|
124
|
+
return this.application.startCompiledTarget({
|
|
125
|
+
compiled,
|
|
126
|
+
metadata: canonicalMetadata(compiled, request),
|
|
127
|
+
...(request.run_id === undefined ? {} : { run_id: request.run_id }),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async startCompiled(request) {
|
|
131
|
+
assertRequiredCapabilities(request.compiled.plan_payload, this.capabilities.driver);
|
|
132
|
+
const metadata = {
|
|
133
|
+
schema_version: HARNESS_RUN_METADATA_SCHEMA_VERSION,
|
|
134
|
+
transport: "harness_pull",
|
|
135
|
+
project_directory: request.project_directory,
|
|
136
|
+
target: request.target,
|
|
137
|
+
compiled_ir: request.compiled.projection === null
|
|
138
|
+
? null
|
|
139
|
+
: durableCanonicalRuntimeProjection(request.compiled.projection),
|
|
140
|
+
requested_metadata: request.metadata ?? null,
|
|
141
|
+
};
|
|
142
|
+
return this.application.startCompiledTarget({
|
|
143
|
+
compiled: request.compiled,
|
|
144
|
+
metadata: JSON.parse(canonicalizeJson(metadata)),
|
|
145
|
+
...(request.run_id === undefined ? {} : { run_id: request.run_id }),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async next(runId) {
|
|
149
|
+
requireText(runId, "run_id");
|
|
150
|
+
const resumed = await this.service.resume(runId);
|
|
151
|
+
assertRequiredCapabilities(resumed.plan.plan, this.capabilities.driver);
|
|
152
|
+
return this.service.acquireAttempt({
|
|
153
|
+
run_id: runId,
|
|
154
|
+
driver_id: this.driverId,
|
|
155
|
+
recover_running: false,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async attach(request) {
|
|
159
|
+
const run = await this.requireAttempt(request.run_id, request.attempt_id);
|
|
160
|
+
this.assertSubmissionMode(run, request.submission_mode);
|
|
161
|
+
try {
|
|
162
|
+
this.validateWorkerSessionId?.(request.worker_session_id);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
throw new HarnessPullAdapterError("invalid_request", "worker_session_id is invalid for this harness host", { cause: error });
|
|
166
|
+
}
|
|
167
|
+
const attached = await this.service.attachAttempt({
|
|
168
|
+
lease_token: request.lease_token,
|
|
169
|
+
owner_id: request.owner_id,
|
|
170
|
+
worker_identity: request.worker_session_id,
|
|
171
|
+
capabilities: this.capabilities.driver,
|
|
172
|
+
});
|
|
173
|
+
if (attached.lease.run_id !== request.run_id
|
|
174
|
+
|| attached.lease.attempt_id !== request.attempt_id
|
|
175
|
+
|| attached.attempt.executor?.kind !== "worker"
|
|
176
|
+
|| attached.attempt.executor.worker_session_id !== request.worker_session_id) {
|
|
177
|
+
throw new HarnessPullAdapterError("invalid_service_response", "attached attempt identity does not match the requested harness lease");
|
|
178
|
+
}
|
|
179
|
+
if (this.capabilities.driver.hook_identity === true) {
|
|
180
|
+
const current = await this.service.inspect(request.run_id);
|
|
181
|
+
await this.attemptProjectionSink?.({
|
|
182
|
+
run: current,
|
|
183
|
+
attached,
|
|
184
|
+
lease_token: request.lease_token,
|
|
185
|
+
owner_id: request.owner_id,
|
|
186
|
+
worker_session_id: request.worker_session_id,
|
|
187
|
+
submission_mode: request.submission_mode,
|
|
188
|
+
metadata: parseHarnessRunMetadata(current.run.metadata),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return attached;
|
|
192
|
+
}
|
|
193
|
+
async heartbeat(request) {
|
|
194
|
+
return this.service.heartbeat(request);
|
|
195
|
+
}
|
|
196
|
+
async submit(request) {
|
|
197
|
+
const run = await this.requireAttempt(request.run_id, request.attempt_id);
|
|
198
|
+
this.assertSubmissionMode(run, request.submission_mode);
|
|
199
|
+
if (request.evidence_refs?.some((evidence) => evidence.kind === "caller_attestation")) {
|
|
200
|
+
throw new HarnessPullAdapterError("invalid_request", "caller attestation cannot be supplied through harness tool arguments");
|
|
201
|
+
}
|
|
202
|
+
const attempt = run.attempts.find((candidate) => candidate.attempt_id === request.attempt_id);
|
|
203
|
+
if (attempt.executor?.kind !== "worker"
|
|
204
|
+
|| request.execution.executor.kind !== "worker"
|
|
205
|
+
|| !sameJson(attempt.executor, request.execution.executor)) {
|
|
206
|
+
throw new HarnessPullAdapterError("invalid_request", "submission executor does not match the attached worker attempt");
|
|
207
|
+
}
|
|
208
|
+
const evidence = [...(request.evidence_refs ?? [])];
|
|
209
|
+
if (request.submission_mode === "attested_independent_submit") {
|
|
210
|
+
evidence.push(await this.attestSubmission(run, request));
|
|
211
|
+
}
|
|
212
|
+
return this.service.submitAttempt({
|
|
213
|
+
lease_token: request.lease_token,
|
|
214
|
+
owner_id: request.owner_id,
|
|
215
|
+
submission_key: request.submission_key,
|
|
216
|
+
execution: request.execution,
|
|
217
|
+
evidence_refs: evidence,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async status(runId) {
|
|
221
|
+
requireText(runId, "run_id");
|
|
222
|
+
return this.service.inspect(runId);
|
|
223
|
+
}
|
|
224
|
+
async cancel(runId, reason) {
|
|
225
|
+
requireText(runId, "run_id");
|
|
226
|
+
if (this.capabilities.driver.cancellation !== true) {
|
|
227
|
+
throw new HarnessPullAdapterError("unsupported", "harness cancellation requires trusted stopped-execution authority");
|
|
228
|
+
}
|
|
229
|
+
return this.service.cancel(runId, reason);
|
|
230
|
+
}
|
|
231
|
+
async requireAttempt(runId, attemptId) {
|
|
232
|
+
requireText(runId, "run_id");
|
|
233
|
+
requireText(attemptId, "attempt_id");
|
|
234
|
+
const run = await this.service.inspect(runId);
|
|
235
|
+
assertRequiredCapabilities(run.plan.plan, this.capabilities.driver);
|
|
236
|
+
if (!run.attempts.some((attempt) => attempt.attempt_id === attemptId)) {
|
|
237
|
+
throw new HarnessPullAdapterError("invalid_request", `attempt ${attemptId} does not belong to run ${runId}`);
|
|
238
|
+
}
|
|
239
|
+
return run;
|
|
240
|
+
}
|
|
241
|
+
assertSubmissionMode(run, mode) {
|
|
242
|
+
if (!this.capabilities.submission_modes.includes(mode)) {
|
|
243
|
+
throw new HarnessPullAdapterError("unsupported", `harness submission mode ${mode} is unavailable`);
|
|
244
|
+
}
|
|
245
|
+
if (run.plan.plan.required_capabilities.caller_attestation
|
|
246
|
+
&& mode !== "attested_independent_submit") {
|
|
247
|
+
throw new HarnessPullAdapterError("unsupported", "this run requires attested_independent_submit");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async attestSubmission(run, request) {
|
|
251
|
+
const authority = this.callerAttestationAuthority;
|
|
252
|
+
if (authority === undefined) {
|
|
253
|
+
throw new HarnessPullAdapterError("unsupported", "trusted caller attestation is unavailable");
|
|
254
|
+
}
|
|
255
|
+
const attempt = run.attempts.find((candidate) => candidate.attempt_id === request.attempt_id);
|
|
256
|
+
const claim = [...run.claims]
|
|
257
|
+
.reverse()
|
|
258
|
+
.find((candidate) => candidate.attempt_id === request.attempt_id);
|
|
259
|
+
if (!claim || claim.owner_id !== request.owner_id) {
|
|
260
|
+
throw new HarnessPullAdapterError("invalid_request", "submission owner does not match the durable attempt claim");
|
|
261
|
+
}
|
|
262
|
+
if (request.execution.executor.kind !== "worker") {
|
|
263
|
+
throw new HarnessPullAdapterError("unsupported", "independent submission currently supports worker attempts only");
|
|
264
|
+
}
|
|
265
|
+
if (attempt.executor?.kind !== "worker"
|
|
266
|
+
|| attempt.executor.worker_session_id !== request.execution.executor.worker_session_id) {
|
|
267
|
+
throw new HarnessPullAdapterError("invalid_request", "submission executor does not match the attached worker attempt");
|
|
268
|
+
}
|
|
269
|
+
const expected = {
|
|
270
|
+
run_id: request.run_id,
|
|
271
|
+
step_id: attempt.step_id,
|
|
272
|
+
activation_id: attempt.activation_id,
|
|
273
|
+
attempt_id: request.attempt_id,
|
|
274
|
+
claim_epoch: claim.claim_epoch,
|
|
275
|
+
worker_session_id: attempt.executor.worker_session_id,
|
|
276
|
+
submission_key_digest: digest({ submission_key: request.submission_key }),
|
|
277
|
+
execution_digest: digest(request.execution),
|
|
278
|
+
};
|
|
279
|
+
const attestation = await authority.attest({
|
|
280
|
+
run,
|
|
281
|
+
submission: {
|
|
282
|
+
attempt,
|
|
283
|
+
claim_epoch: claim.claim_epoch,
|
|
284
|
+
submission_key_digest: expected.submission_key_digest,
|
|
285
|
+
execution_digest: expected.execution_digest,
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
const payload = attestation.payload;
|
|
289
|
+
if (authority.authority_id.length === 0
|
|
290
|
+
|| payload.schema_version !== HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION
|
|
291
|
+
|| payload.authority_id !== authority.authority_id
|
|
292
|
+
|| !payload.agent_id
|
|
293
|
+
|| !payload.session_id
|
|
294
|
+
|| !sameJson({
|
|
295
|
+
run_id: payload.run_id,
|
|
296
|
+
step_id: payload.step_id,
|
|
297
|
+
activation_id: payload.activation_id,
|
|
298
|
+
attempt_id: payload.attempt_id,
|
|
299
|
+
claim_epoch: payload.claim_epoch,
|
|
300
|
+
worker_session_id: payload.worker_session_id,
|
|
301
|
+
submission_key_digest: payload.submission_key_digest,
|
|
302
|
+
execution_digest: payload.execution_digest,
|
|
303
|
+
}, expected)
|
|
304
|
+
|| !attestation.attestation_ref
|
|
305
|
+
|| attestation.attestation_digest !== harnessCallerAttestationDigest(payload)) {
|
|
306
|
+
throw new HarnessPullAdapterError("invalid_request", "caller attestation does not match the durable attempt submission");
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
kind: "caller_attestation",
|
|
310
|
+
attestation_ref: attestation.attestation_ref,
|
|
311
|
+
attestation_digest: attestation.attestation_digest,
|
|
312
|
+
payload,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|