codai-sdk 0.6.0 → 0.7.0
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/README.md +18 -0
- package/dist/index.d.ts +138 -1
- package/dist/index.js +117 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -226,6 +226,24 @@ if (!verifyResolveWebhook(secret, raw, req.headers.get('x-codai-signature'))) {
|
|
|
226
226
|
const evt = JSON.parse(raw) as ResolveWebhookEvent; // evt.event, evt.job.attestation_url
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
+
### Verifying a signed attestation
|
|
230
|
+
|
|
231
|
+
Attestations created from 2026-09-27 carry `signature`: a DSSE envelope
|
|
232
|
+
(ECDSA P-256/SHA-256) over a canonical statement of sha256 hashes of the patch,
|
|
233
|
+
repro test and test outputs, plus the commands, base commit, runner digest and
|
|
234
|
+
timestamps. `verifyAttestation` checks the signature against
|
|
235
|
+
`GET /v1/resolve/keys` **and** that the statement matches the fields you were
|
|
236
|
+
served. Older attestations have `signature: null` → `{ ok: false, reason: 'UNSIGNED' }`.
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const proof = await codai.resolve.attestation(job.attestation_url!);
|
|
240
|
+
const r = await codai.resolve.verifyAttestation(proof); // or { keys: pinnedKeys }
|
|
241
|
+
if (!r.ok) throw new Error(`attestation not verified: ${r.reason}`);
|
|
242
|
+
// r.keyid — the signing key; reasons: UNSIGNED | BAD_SIGNATURE | STATEMENT_MISMATCH | BAD_PAYLOAD_TYPE
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Offline (no network): `verifyAttestationWithKeys(proof, keys)`. Server-side only (`node:crypto`).
|
|
246
|
+
|
|
229
247
|
## Shared sessions, devices and hosts
|
|
230
248
|
|
|
231
249
|
Shared-sessions and hosts calls need a device UUID (`x-codai-device`). Set it once
|
package/dist/index.d.ts
CHANGED
|
@@ -11024,6 +11024,30 @@ type paths = {
|
|
|
11024
11024
|
readonly patch?: never;
|
|
11025
11025
|
readonly trace?: never;
|
|
11026
11026
|
};
|
|
11027
|
+
readonly '/v1/resolve/keys': {
|
|
11028
|
+
readonly parameters: {
|
|
11029
|
+
readonly query?: never;
|
|
11030
|
+
readonly header?: never;
|
|
11031
|
+
readonly path?: never;
|
|
11032
|
+
readonly cookie?: never;
|
|
11033
|
+
};
|
|
11034
|
+
/**
|
|
11035
|
+
* Public keys that sign attestations
|
|
11036
|
+
* @description Returns the public key(s) used to sign attestation envelopes (`signature` on
|
|
11037
|
+
* `GET /v1/resolve/attestations/{id}`). ECDSA P-256 / SHA-256 over the DSSE v1 PAE of the
|
|
11038
|
+
* payload; the signature is DER, base64. **Unauthenticated**, CORS-open and cacheable for
|
|
11039
|
+
* 1 hour. Verify with `codaid resolve verify`, `resolve.verifyAttestation` (TypeScript) or
|
|
11040
|
+
* `resolve.verify_attestation` (Python). `503` when signing is not configured.
|
|
11041
|
+
*/
|
|
11042
|
+
readonly get: operations['getResolveKeys'];
|
|
11043
|
+
readonly put?: never;
|
|
11044
|
+
readonly post?: never;
|
|
11045
|
+
readonly delete?: never;
|
|
11046
|
+
readonly options?: never;
|
|
11047
|
+
readonly head?: never;
|
|
11048
|
+
readonly patch?: never;
|
|
11049
|
+
readonly trace?: never;
|
|
11050
|
+
};
|
|
11027
11051
|
};
|
|
11028
11052
|
type components = {
|
|
11029
11053
|
schemas: {
|
|
@@ -11059,6 +11083,13 @@ type components = {
|
|
|
11059
11083
|
readonly repro_test: components['schemas']['ResolveReproTest'] | null;
|
|
11060
11084
|
/** @description Container image digest of the verification runner (`unknown` when not recorded). */
|
|
11061
11085
|
readonly runner_image_digest: string;
|
|
11086
|
+
/**
|
|
11087
|
+
* @description DSSE envelope signing the canonical statement of this attestation (sha256 of the patch,
|
|
11088
|
+
* repro test, test outputs; commands, commit, runner digest, timestamps). `null` for
|
|
11089
|
+
* attestations created before signing was enabled (2026-09-27). Verify against
|
|
11090
|
+
* `GET /v1/resolve/keys`.
|
|
11091
|
+
*/
|
|
11092
|
+
readonly signature: components['schemas']['ResolveAttestationEnvelope'] | null;
|
|
11062
11093
|
/** Format: date-time */
|
|
11063
11094
|
readonly started_at: string;
|
|
11064
11095
|
/** @description FAIL_TO_PASS command that was executed. */
|
|
@@ -11070,6 +11101,28 @@ type components = {
|
|
|
11070
11101
|
/** Format: date-time */
|
|
11071
11102
|
readonly verified_at: string;
|
|
11072
11103
|
};
|
|
11104
|
+
/**
|
|
11105
|
+
* Attestation envelope
|
|
11106
|
+
* @description DSSE v1 envelope. `payload` is base64 of the RFC 8785 (JCS) canonical statement JSON
|
|
11107
|
+
* `{kind: "codai.resolve.attestation.v1", attestation_id, repo_url, base_commit, patch_sha256,
|
|
11108
|
+
* repro_test: {path, sha256} | null, test_command, regression_command,
|
|
11109
|
+
* test_output_before_sha256, test_output_after_sha256, regression_output_sha256,
|
|
11110
|
+
* runner_image_digest, started_at, verified_at}`. Each `sig` is an ECDSA P-256/SHA-256 DER
|
|
11111
|
+
* signature (base64) over `PAE(payloadType, payload bytes)` =
|
|
11112
|
+
* `"DSSEv1 " + len(type) + " " + type + " " + len(body) + " " + body`.
|
|
11113
|
+
*/
|
|
11114
|
+
readonly ResolveAttestationEnvelope: {
|
|
11115
|
+
/** @description Base64 of the canonical statement JSON. */
|
|
11116
|
+
readonly payload: string;
|
|
11117
|
+
/** @constant */
|
|
11118
|
+
readonly payloadType: 'application/vnd.codai.resolve.attestation+json;v=1';
|
|
11119
|
+
readonly signatures: readonly {
|
|
11120
|
+
/** @description Identifier of the signing key; matches `keyid` in `GET /v1/resolve/keys`. */
|
|
11121
|
+
readonly keyid?: string;
|
|
11122
|
+
/** @description DER-encoded ECDSA signature, base64. */
|
|
11123
|
+
readonly sig: string;
|
|
11124
|
+
}[];
|
|
11125
|
+
};
|
|
11073
11126
|
/**
|
|
11074
11127
|
* Declined
|
|
11075
11128
|
* @description `200` body — triage declined the issue. The job is persisted with `status: declined` and is never billed.
|
|
@@ -11213,6 +11266,26 @@ type components = {
|
|
|
11213
11266
|
* @enum {string}
|
|
11214
11267
|
*/
|
|
11215
11268
|
readonly ResolveJobStatus: 'triage' | 'quoted' | 'declined' | 'accepted' | 'running' | 'resolved' | 'failed' | 'error';
|
|
11269
|
+
/** Verification key */
|
|
11270
|
+
readonly ResolveKey: {
|
|
11271
|
+
/** @constant */
|
|
11272
|
+
readonly algorithm: 'ECDSA_P256_SHA256';
|
|
11273
|
+
/**
|
|
11274
|
+
* @description Envelope and signature encoding.
|
|
11275
|
+
* @example DSSE v1; signature DER, base64
|
|
11276
|
+
*/
|
|
11277
|
+
readonly encoding: string;
|
|
11278
|
+
/** @description Key identifier (the Cloud KMS key version name). */
|
|
11279
|
+
readonly keyid: string;
|
|
11280
|
+
/** @constant */
|
|
11281
|
+
readonly payload_type: 'application/vnd.codai.resolve.attestation+json;v=1';
|
|
11282
|
+
/** @description SPKI public key, PEM. */
|
|
11283
|
+
readonly public_key_pem: string;
|
|
11284
|
+
};
|
|
11285
|
+
/** Verification keys */
|
|
11286
|
+
readonly ResolveKeys: {
|
|
11287
|
+
readonly keys: readonly components['schemas']['ResolveKey'][];
|
|
11288
|
+
};
|
|
11216
11289
|
/**
|
|
11217
11290
|
* Quote
|
|
11218
11291
|
* @description `201` body — the job was quoted (`quoted`) or auto-accepted on the free tier (`accepted`).
|
|
@@ -11541,6 +11614,35 @@ interface operations {
|
|
|
11541
11614
|
readonly 409: components['responses']['ResolveConflict'];
|
|
11542
11615
|
};
|
|
11543
11616
|
};
|
|
11617
|
+
readonly getResolveKeys: {
|
|
11618
|
+
readonly parameters: {
|
|
11619
|
+
readonly query?: never;
|
|
11620
|
+
readonly header?: never;
|
|
11621
|
+
readonly path?: never;
|
|
11622
|
+
readonly cookie?: never;
|
|
11623
|
+
};
|
|
11624
|
+
readonly requestBody?: never;
|
|
11625
|
+
readonly responses: {
|
|
11626
|
+
/** @description Current verification keys. */
|
|
11627
|
+
readonly 200: {
|
|
11628
|
+
headers: {
|
|
11629
|
+
readonly [name: string]: unknown;
|
|
11630
|
+
};
|
|
11631
|
+
content: {
|
|
11632
|
+
readonly 'application/json': components['schemas']['ResolveKeys'];
|
|
11633
|
+
};
|
|
11634
|
+
};
|
|
11635
|
+
/** @description Attestation signing is not configured (`attestation signing not configured`). */
|
|
11636
|
+
readonly 503: {
|
|
11637
|
+
headers: {
|
|
11638
|
+
readonly [name: string]: unknown;
|
|
11639
|
+
};
|
|
11640
|
+
content: {
|
|
11641
|
+
readonly 'application/json': components['schemas']['ResolveError'];
|
|
11642
|
+
};
|
|
11643
|
+
};
|
|
11644
|
+
};
|
|
11645
|
+
};
|
|
11544
11646
|
readonly resolveJobWebhook: {
|
|
11545
11647
|
readonly parameters: {
|
|
11546
11648
|
readonly query?: never;
|
|
@@ -11592,6 +11694,10 @@ type ResolveJob = ResolveSchemas['ResolveJob'];
|
|
|
11592
11694
|
type ResolveJobStatus = ResolveSchemas['ResolveJobStatus'];
|
|
11593
11695
|
type ResolveTier = ResolveSchemas['ResolveTier'];
|
|
11594
11696
|
type ResolveAttestation = ResolveSchemas['ResolveAttestation'];
|
|
11697
|
+
/** DSSE v1 envelope in `ResolveAttestation.signature` (`null` = unsigned, pre-2026-09-27). */
|
|
11698
|
+
type ResolveAttestationEnvelope = ResolveSchemas['ResolveAttestationEnvelope'];
|
|
11699
|
+
type ResolveKeys = ResolveSchemas['ResolveKeys'];
|
|
11700
|
+
type ResolveKey = ResolveSchemas['ResolveKey'];
|
|
11595
11701
|
type ResolveReproTest = ResolveSchemas['ResolveReproTest'];
|
|
11596
11702
|
type ResolveHealth = ResolveSchemas['ResolveHealth'];
|
|
11597
11703
|
type ResolveValidationDetails = ResolveSchemas['ResolveValidationDetails'];
|
|
@@ -11617,6 +11723,25 @@ interface VerifyResolveWebhookOptions {
|
|
|
11617
11723
|
* Throws only when `node:crypto` is unavailable in the current runtime.
|
|
11618
11724
|
*/
|
|
11619
11725
|
declare function verifyResolveWebhook(secret: string, rawBody: string | Uint8Array, signatureHeader: string | null | undefined, opts?: VerifyResolveWebhookOptions): boolean;
|
|
11726
|
+
/** `payloadType` of Resolve attestation envelopes. */
|
|
11727
|
+
declare const RESOLVE_ATTESTATION_PAYLOAD_TYPE = "application/vnd.codai.resolve.attestation+json;v=1";
|
|
11728
|
+
type ResolveAttestationVerifyResult = {
|
|
11729
|
+
ok: true;
|
|
11730
|
+
keyid: string;
|
|
11731
|
+
} | {
|
|
11732
|
+
ok: false;
|
|
11733
|
+
reason: 'UNSIGNED' | 'BAD_SIGNATURE' | 'STATEMENT_MISMATCH' | 'BAD_PAYLOAD_TYPE';
|
|
11734
|
+
};
|
|
11735
|
+
/** The statement the Resolve service signs, recomputed from the attestation JSON. */
|
|
11736
|
+
declare function resolveAttestationStatement(att: ResolveAttestation): Record<string, unknown>;
|
|
11737
|
+
/**
|
|
11738
|
+
* Verify a Resolve attestation offline against published keys: the DSSE
|
|
11739
|
+
* signature (ECDSA P-256/SHA-256, DER) over `PAE(payloadType, payload)` must
|
|
11740
|
+
* match one key, AND the signed statement must equal the one recomputed from
|
|
11741
|
+
* the attestation's own fields (so a valid signature over other content fails).
|
|
11742
|
+
* Server-side only (`node:crypto`, loaded lazily).
|
|
11743
|
+
*/
|
|
11744
|
+
declare function verifyAttestationWithKeys(att: ResolveAttestation, keys: ResolveKeys): ResolveAttestationVerifyResult;
|
|
11620
11745
|
/** Statuses after which a job never changes again. */
|
|
11621
11746
|
declare const RESOLVE_TERMINAL_STATUSES: ReadonlySet<ResolveJobStatus>;
|
|
11622
11747
|
/** Any non-2xx answer from the Resolve service (flat `{ error }` body). */
|
|
@@ -11680,6 +11805,18 @@ declare class Resolve {
|
|
|
11680
11805
|
attestation(idOrUrl: string, opts?: CallOpts$4): Promise<ResolveAttestation>;
|
|
11681
11806
|
/** `GET /health` — liveness of the Resolve service. */
|
|
11682
11807
|
health(opts?: CallOpts$4): Promise<ResolveHealth>;
|
|
11808
|
+
/** `GET /v1/resolve/keys` — public keys that sign attestations (no auth needed server-side). */
|
|
11809
|
+
keys(opts?: CallOpts$4): Promise<ResolveKeys>;
|
|
11810
|
+
/**
|
|
11811
|
+
* Verify an attestation's signature and that the signed statement matches
|
|
11812
|
+
* its fields. Fetches `keys()` unless `opts.keys` is given (pin them to
|
|
11813
|
+
* avoid trusting the network). `{ ok: false, reason: 'UNSIGNED' }` for
|
|
11814
|
+
* attestations created before signing (2026-09-27). Server-side only.
|
|
11815
|
+
*/
|
|
11816
|
+
verifyAttestation(att: ResolveAttestation, opts?: {
|
|
11817
|
+
keys?: ResolveKeys;
|
|
11818
|
+
signal?: AbortSignal;
|
|
11819
|
+
}): Promise<ResolveAttestationVerifyResult>;
|
|
11683
11820
|
/**
|
|
11684
11821
|
* Poll `get(id)` until the job reaches a terminal status (`resolved`,
|
|
11685
11822
|
* `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
|
|
@@ -12186,4 +12323,4 @@ declare class Codai {
|
|
|
12186
12323
|
private legacyExt;
|
|
12187
12324
|
}
|
|
12188
12325
|
|
|
12189
|
-
export { Account, type AccountPatchRequest, type AccountPatchResponse, type AccountView, type AgentRun, type AgentRunAccepted, type AgentRunCreateRequest, type AgentRunRequest, type AgentRunResult, type AgentRunStats, type AgentRunStatus, type AgentRunStep, type AgentRunStreamEvent, AgentRuns, type AgentSyncResult, Agents, Audio, Chat, type ChatCallOptions, type ChatCompletionChunk, type ChatCompletionInput, type ChatCompletionRequest, type ChatCompletionResponse, ChatCompletions, type ChatMessage, type ChatOptions, type ChatResult, type ChatStream, type ChatStreamResult, type ChatTool, type ChatToolCall, type ChatUsage, Codai, type CodaiClientOptions, CodaiError, type CodaiRequestExtensions, type Device, type DevicePatch, type DevicePatched, Devices, type DispatchInbox, Embeddings, type EmbeddingsOptions, type EmbeddingsRequest, type EmbeddingsResponse, type EmbeddingsResult, type Environment, type EnvironmentAddMemberBody, type EnvironmentCreateBody, type EnvironmentDetail, type EnvironmentEnrollBody, type EnvironmentEnrollToken, type EnvironmentEnrolled, type EnvironmentMember, type EnvironmentMemberCreated, EnvironmentMembers, type EnvironmentPatchBody, type EnvironmentPort, type EnvironmentPortBody, EnvironmentPorts, type EnvironmentProvider, type EnvironmentRole, type EnvironmentSecret, type EnvironmentSecretSet, EnvironmentSecrets, type EnvironmentSshCa, type EnvironmentSshCert, type EnvironmentSshCertBody, type EnvironmentState, type EnvironmentTaskCreateBody, type EnvironmentTaskCreated, type EnvironmentTaskDetail, type EnvironmentTaskList, EnvironmentTasks, type EnvironmentTransition, Environments, type EphemeralScope, type EphemeralToken, type EphemeralTokenResponse, type ErrorCode, Feedback, type FeedbackRequest, type FeedbackResponse, Health, type HealthReadyResponse, type HealthResponse, type HostExecBody, type HostExecRequest, type HostExecResponse, type HostExecResultBody, type HostOp, type HostPresence, type HostStreamEvent, Hosts, HttpClient, type ListEnvironmentsQuery, type MessageCallOptions, type MessageInput, type MessageRequest, type MessageResponse, type MessageResult, type MessageStream, type MessageStreamEvent, type MessageStreamResult, Messages, type Model, type ModelList, Models, type NotificationList, Notifications, type NotificationsDeleted, type NotificationsRead, OPERATION_METHODS, type Org, type OrgAddMemberBody, type OrgMember, OrgMembers, type OrgRole, Orgs, type PhoneModel, PhoneModels, type Project, type ProjectCreateBody, type ProjectDetail, type ProjectIsolation, type ProjectPatchBody, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, type Receipt, Receipts, type RequestOptions, Resolve, type ResolveAccepted, type ResolveAttestation, type components as ResolveComponents, type ResolveDeclined, ResolveError, type ResolveHealth, type ResolveInsufficientFunds, ResolveInsufficientFundsError, type ResolveIntake, type ResolveJob, type ResolveJobStatus, type operations as ResolveOperations, type paths as ResolvePaths, type ResolveQuote, type ResolveReproTest, type ResolveSubmitResult, type ResolveTier, type ResolveValidationDetails, type ResolveWaitOptions, type ResolveWebhookEvent, type ResolveWebhookEventName, type ResolveWebhookJob, Responses, type ResponsesCallOptions, type ResponsesInput, type ResponsesRequest, type ResponsesResponse, type ResponsesResult, type ResponsesStream, type ResponsesStreamEvent, type ResponsesStreamResult, STREAMING_OPERATIONS, type Session, type SessionControl, type SessionControlAccepted, type SessionControlRequest, SessionControls, type SessionCreateRequest, type SessionDetail, type SessionDispatchRequest, type SessionDispatchResponse, type SessionEvent, SessionEvents, type SessionEventsAppendRequest, type SessionEventsAppendResponse, type SessionEventsPage, type SessionIncomingEvent, SessionLease, type SessionLeaseClaimRequest, type SessionLeaseResponse, type SessionListItem, type SessionPatchRequest, type SessionShare, type SessionShareCreateRequest, type SessionShareCreated, SessionShares, type SessionStreamEvent, Sessions, type SharedSession, type SpeechRequest, type SpeechResult, type SseFrame, type StatusResponse, type Task, type TaskConfirmRequest, type TaskConfirmResponse, type TaskListPage, type TaskListQuery, type TaskOutcome, type TaskStats, Tasks, type TokenUsage, Tokens, type ToolFetchRequest, type ToolFetchResponse, type ToolSearchRequest, type ToolSearchResponse, Tools, type TranscriptionOptions, type TranscriptionResponse, type TranscriptionResult, type TriggerCreateRequest, type TriggerCreated, type TriggerEvents, type TriggerList, type TriggerPatch, type TriggerTestRequest, type TriggerTestResult, type TriggerUpdated, Triggers, type VerifyResolveWebhookOptions, type components$1 as components, Codai as default, extensionHeaders, frameJson, mergeToolCall, type operations$1 as operations, type paths$1 as paths, readSse, verifyResolveWebhook };
|
|
12326
|
+
export { Account, type AccountPatchRequest, type AccountPatchResponse, type AccountView, type AgentRun, type AgentRunAccepted, type AgentRunCreateRequest, type AgentRunRequest, type AgentRunResult, type AgentRunStats, type AgentRunStatus, type AgentRunStep, type AgentRunStreamEvent, AgentRuns, type AgentSyncResult, Agents, Audio, Chat, type ChatCallOptions, type ChatCompletionChunk, type ChatCompletionInput, type ChatCompletionRequest, type ChatCompletionResponse, ChatCompletions, type ChatMessage, type ChatOptions, type ChatResult, type ChatStream, type ChatStreamResult, type ChatTool, type ChatToolCall, type ChatUsage, Codai, type CodaiClientOptions, CodaiError, type CodaiRequestExtensions, type Device, type DevicePatch, type DevicePatched, Devices, type DispatchInbox, Embeddings, type EmbeddingsOptions, type EmbeddingsRequest, type EmbeddingsResponse, type EmbeddingsResult, type Environment, type EnvironmentAddMemberBody, type EnvironmentCreateBody, type EnvironmentDetail, type EnvironmentEnrollBody, type EnvironmentEnrollToken, type EnvironmentEnrolled, type EnvironmentMember, type EnvironmentMemberCreated, EnvironmentMembers, type EnvironmentPatchBody, type EnvironmentPort, type EnvironmentPortBody, EnvironmentPorts, type EnvironmentProvider, type EnvironmentRole, type EnvironmentSecret, type EnvironmentSecretSet, EnvironmentSecrets, type EnvironmentSshCa, type EnvironmentSshCert, type EnvironmentSshCertBody, type EnvironmentState, type EnvironmentTaskCreateBody, type EnvironmentTaskCreated, type EnvironmentTaskDetail, type EnvironmentTaskList, EnvironmentTasks, type EnvironmentTransition, Environments, type EphemeralScope, type EphemeralToken, type EphemeralTokenResponse, type ErrorCode, Feedback, type FeedbackRequest, type FeedbackResponse, Health, type HealthReadyResponse, type HealthResponse, type HostExecBody, type HostExecRequest, type HostExecResponse, type HostExecResultBody, type HostOp, type HostPresence, type HostStreamEvent, Hosts, HttpClient, type ListEnvironmentsQuery, type MessageCallOptions, type MessageInput, type MessageRequest, type MessageResponse, type MessageResult, type MessageStream, type MessageStreamEvent, type MessageStreamResult, Messages, type Model, type ModelList, Models, type NotificationList, Notifications, type NotificationsDeleted, type NotificationsRead, OPERATION_METHODS, type Org, type OrgAddMemberBody, type OrgMember, OrgMembers, type OrgRole, Orgs, type PhoneModel, PhoneModels, type Project, type ProjectCreateBody, type ProjectDetail, type ProjectIsolation, type ProjectPatchBody, Projects, RESOLVE_ATTESTATION_PAYLOAD_TYPE, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, type Receipt, Receipts, type RequestOptions, Resolve, type ResolveAccepted, type ResolveAttestation, type ResolveAttestationEnvelope, type ResolveAttestationVerifyResult, type components as ResolveComponents, type ResolveDeclined, ResolveError, type ResolveHealth, type ResolveInsufficientFunds, ResolveInsufficientFundsError, type ResolveIntake, type ResolveJob, type ResolveJobStatus, type ResolveKey, type ResolveKeys, type operations as ResolveOperations, type paths as ResolvePaths, type ResolveQuote, type ResolveReproTest, type ResolveSubmitResult, type ResolveTier, type ResolveValidationDetails, type ResolveWaitOptions, type ResolveWebhookEvent, type ResolveWebhookEventName, type ResolveWebhookJob, Responses, type ResponsesCallOptions, type ResponsesInput, type ResponsesRequest, type ResponsesResponse, type ResponsesResult, type ResponsesStream, type ResponsesStreamEvent, type ResponsesStreamResult, STREAMING_OPERATIONS, type Session, type SessionControl, type SessionControlAccepted, type SessionControlRequest, SessionControls, type SessionCreateRequest, type SessionDetail, type SessionDispatchRequest, type SessionDispatchResponse, type SessionEvent, SessionEvents, type SessionEventsAppendRequest, type SessionEventsAppendResponse, type SessionEventsPage, type SessionIncomingEvent, SessionLease, type SessionLeaseClaimRequest, type SessionLeaseResponse, type SessionListItem, type SessionPatchRequest, type SessionShare, type SessionShareCreateRequest, type SessionShareCreated, SessionShares, type SessionStreamEvent, Sessions, type SharedSession, type SpeechRequest, type SpeechResult, type SseFrame, type StatusResponse, type Task, type TaskConfirmRequest, type TaskConfirmResponse, type TaskListPage, type TaskListQuery, type TaskOutcome, type TaskStats, Tasks, type TokenUsage, Tokens, type ToolFetchRequest, type ToolFetchResponse, type ToolSearchRequest, type ToolSearchResponse, Tools, type TranscriptionOptions, type TranscriptionResponse, type TranscriptionResult, type TriggerCreateRequest, type TriggerCreated, type TriggerEvents, type TriggerList, type TriggerPatch, type TriggerTestRequest, type TriggerTestResult, type TriggerUpdated, Triggers, type VerifyResolveWebhookOptions, type components$1 as components, Codai as default, extensionHeaders, frameJson, mergeToolCall, type operations$1 as operations, type paths$1 as paths, readSse, resolveAttestationStatement, verifyAttestationWithKeys, verifyResolveWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1260,6 +1260,105 @@ function hexToBytes(hex) {
|
|
|
1260
1260
|
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
1261
1261
|
return out;
|
|
1262
1262
|
}
|
|
1263
|
+
var RESOLVE_ATTESTATION_PAYLOAD_TYPE = "application/vnd.codai.resolve.attestation+json;v=1";
|
|
1264
|
+
function verifyCrypto() {
|
|
1265
|
+
const proc = globalThis.process;
|
|
1266
|
+
const mod = proc?.getBuiltinModule?.("node:crypto");
|
|
1267
|
+
if (!mod) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
"verifyAttestation needs node:crypto (Node 20.16+/22.3+, Bun or Deno); run it server-side"
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
return mod;
|
|
1273
|
+
}
|
|
1274
|
+
function canonicalJson(v) {
|
|
1275
|
+
if (v === null || typeof v !== "object") return JSON.stringify(v);
|
|
1276
|
+
if (Array.isArray(v)) return `[${v.map(canonicalJson).join(",")}]`;
|
|
1277
|
+
const o = v;
|
|
1278
|
+
return `{${Object.keys(o).filter((k) => o[k] !== void 0).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(o[k])}`).join(",")}}`;
|
|
1279
|
+
}
|
|
1280
|
+
function base64ToBytes(b64) {
|
|
1281
|
+
const bin = atob(b64);
|
|
1282
|
+
const out = new Uint8Array(bin.length);
|
|
1283
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
1284
|
+
return out;
|
|
1285
|
+
}
|
|
1286
|
+
function pae(payloadType, body) {
|
|
1287
|
+
const enc2 = new TextEncoder();
|
|
1288
|
+
const typeBytes = enc2.encode(payloadType);
|
|
1289
|
+
const head = enc2.encode(`DSSEv1 ${typeBytes.length} ${payloadType} ${body.length} `);
|
|
1290
|
+
const out = new Uint8Array(head.length + body.length);
|
|
1291
|
+
out.set(head, 0);
|
|
1292
|
+
out.set(body, head.length);
|
|
1293
|
+
return out;
|
|
1294
|
+
}
|
|
1295
|
+
function resolveAttestationStatement(att) {
|
|
1296
|
+
const { createHash } = verifyCrypto();
|
|
1297
|
+
const enc2 = new TextEncoder();
|
|
1298
|
+
const sha = (s) => s == null ? null : createHash("sha256").update(enc2.encode(s)).digest("hex");
|
|
1299
|
+
return {
|
|
1300
|
+
kind: "codai.resolve.attestation.v1",
|
|
1301
|
+
attestation_id: att.id,
|
|
1302
|
+
repo_url: att.repo_url,
|
|
1303
|
+
base_commit: att.base_commit,
|
|
1304
|
+
patch_sha256: sha(att.patch),
|
|
1305
|
+
repro_test: att.repro_test?.path ? { path: att.repro_test.path, sha256: sha(att.repro_test.content) } : null,
|
|
1306
|
+
test_command: att.test_command,
|
|
1307
|
+
regression_command: att.regression_command,
|
|
1308
|
+
test_output_before_sha256: sha(att.test_output_before),
|
|
1309
|
+
test_output_after_sha256: sha(att.test_output_after),
|
|
1310
|
+
regression_output_sha256: sha(att.regression_output),
|
|
1311
|
+
runner_image_digest: att.runner_image_digest,
|
|
1312
|
+
started_at: att.started_at,
|
|
1313
|
+
verified_at: att.verified_at
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
function verifyAttestationWithKeys(att, keys) {
|
|
1317
|
+
const env = att.signature;
|
|
1318
|
+
if (!env || !Array.isArray(env.signatures) || env.signatures.length === 0)
|
|
1319
|
+
return { ok: false, reason: "UNSIGNED" };
|
|
1320
|
+
if (env.payloadType !== RESOLVE_ATTESTATION_PAYLOAD_TYPE)
|
|
1321
|
+
return { ok: false, reason: "BAD_PAYLOAD_TYPE" };
|
|
1322
|
+
const { createVerify } = verifyCrypto();
|
|
1323
|
+
let body;
|
|
1324
|
+
try {
|
|
1325
|
+
body = base64ToBytes(env.payload);
|
|
1326
|
+
} catch {
|
|
1327
|
+
return { ok: false, reason: "BAD_SIGNATURE" };
|
|
1328
|
+
}
|
|
1329
|
+
const msg = pae(env.payloadType, body);
|
|
1330
|
+
let keyid = null;
|
|
1331
|
+
outer: for (const s of env.signatures) {
|
|
1332
|
+
let sig;
|
|
1333
|
+
try {
|
|
1334
|
+
sig = base64ToBytes(s.sig);
|
|
1335
|
+
} catch {
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
for (const k of keys.keys) {
|
|
1339
|
+
if (k.payload_type && k.payload_type !== env.payloadType) continue;
|
|
1340
|
+
try {
|
|
1341
|
+
const v = createVerify("SHA256");
|
|
1342
|
+
v.update(msg);
|
|
1343
|
+
if (v.verify({ key: k.public_key_pem, dsaEncoding: "der" }, sig)) {
|
|
1344
|
+
keyid = k.keyid;
|
|
1345
|
+
break outer;
|
|
1346
|
+
}
|
|
1347
|
+
} catch {
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (keyid === null) return { ok: false, reason: "BAD_SIGNATURE" };
|
|
1352
|
+
let signed;
|
|
1353
|
+
try {
|
|
1354
|
+
signed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(body));
|
|
1355
|
+
} catch {
|
|
1356
|
+
return { ok: false, reason: "STATEMENT_MISMATCH" };
|
|
1357
|
+
}
|
|
1358
|
+
if (canonicalJson(signed) !== canonicalJson(resolveAttestationStatement(att)))
|
|
1359
|
+
return { ok: false, reason: "STATEMENT_MISMATCH" };
|
|
1360
|
+
return { ok: true, keyid };
|
|
1361
|
+
}
|
|
1263
1362
|
var RESOLVE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
1264
1363
|
"resolved",
|
|
1265
1364
|
"failed",
|
|
@@ -1347,6 +1446,21 @@ var Resolve = class {
|
|
|
1347
1446
|
health(opts = {}) {
|
|
1348
1447
|
return this.call("/health", { signal: opts.signal });
|
|
1349
1448
|
}
|
|
1449
|
+
/** `GET /v1/resolve/keys` — public keys that sign attestations (no auth needed server-side). */
|
|
1450
|
+
keys(opts = {}) {
|
|
1451
|
+
return this.call("/v1/resolve/keys", { signal: opts.signal });
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Verify an attestation's signature and that the signed statement matches
|
|
1455
|
+
* its fields. Fetches `keys()` unless `opts.keys` is given (pin them to
|
|
1456
|
+
* avoid trusting the network). `{ ok: false, reason: 'UNSIGNED' }` for
|
|
1457
|
+
* attestations created before signing (2026-09-27). Server-side only.
|
|
1458
|
+
*/
|
|
1459
|
+
async verifyAttestation(att, opts = {}) {
|
|
1460
|
+
if (!att.signature) return { ok: false, reason: "UNSIGNED" };
|
|
1461
|
+
const keys = opts.keys ?? await this.keys({ signal: opts.signal });
|
|
1462
|
+
return verifyAttestationWithKeys(att, keys);
|
|
1463
|
+
}
|
|
1350
1464
|
/**
|
|
1351
1465
|
* Poll `get(id)` until the job reaches a terminal status (`resolved`,
|
|
1352
1466
|
* `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
|
|
@@ -2059,7 +2173,8 @@ var RESOLVE_OPERATION_METHODS = {
|
|
|
2059
2173
|
createResolveJob: "resolve.submit",
|
|
2060
2174
|
getResolveJob: "resolve.get",
|
|
2061
2175
|
acceptResolveJob: "resolve.accept",
|
|
2062
|
-
getResolveAttestation: "resolve.attestation"
|
|
2176
|
+
getResolveAttestation: "resolve.attestation",
|
|
2177
|
+
getResolveKeys: "resolve.keys"
|
|
2063
2178
|
};
|
|
2064
2179
|
|
|
2065
2180
|
// src/index.ts
|
|
@@ -2227,6 +2342,6 @@ function allKeys(obj) {
|
|
|
2227
2342
|
}
|
|
2228
2343
|
var index_default = Codai;
|
|
2229
2344
|
|
|
2230
|
-
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse, verifyResolveWebhook };
|
|
2345
|
+
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_ATTESTATION_PAYLOAD_TYPE, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse, resolveAttestationStatement, verifyAttestationWithKeys, verifyResolveWebhook };
|
|
2231
2346
|
//# sourceMappingURL=index.js.map
|
|
2232
2347
|
//# sourceMappingURL=index.js.map
|