@enactprotocol/api 2.0.0 → 2.0.1

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.
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Attestation management (v2)
3
+ * Functions for managing auditor attestations
4
+ */
5
+ import type { OIDCIdentity, SigstoreBundle } from "@enactprotocol/trust";
6
+ import type { EnactApiClient } from "./client";
7
+ import type { Attestation } from "./types";
8
+ /**
9
+ * Verified auditor info with full identity details
10
+ */
11
+ export interface VerifiedAuditor {
12
+ /** Email from attestation */
13
+ email: string;
14
+ /** Full identity from verified certificate (may be undefined if not extractable) */
15
+ identity: OIDCIdentity | undefined;
16
+ /** Provider:identity format (e.g., github:keithagroves) */
17
+ providerIdentity: string;
18
+ }
19
+ /**
20
+ * Attestation list response
21
+ */
22
+ export interface AttestationListResponse {
23
+ attestations: Attestation[];
24
+ total: number;
25
+ limit: number;
26
+ offset: number;
27
+ }
28
+ /**
29
+ * Get all attestations for a tool version (v2)
30
+ *
31
+ * @param client - API client instance
32
+ * @param name - Tool name
33
+ * @param version - Tool version
34
+ * @param options - Pagination options
35
+ * @returns List of attestations with pagination info
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const result = await getAttestations(client, "alice/utils/greeter", "1.2.0", {
40
+ * limit: 10,
41
+ * offset: 0
42
+ * });
43
+ * console.log(`Found ${result.total} attestations`);
44
+ * ```
45
+ */
46
+ export declare function getAttestations(client: EnactApiClient, name: string, version: string, options?: {
47
+ limit?: number | undefined;
48
+ offset?: number | undefined;
49
+ }): Promise<AttestationListResponse>;
50
+ /**
51
+ * Submit an attestation for a tool version (v2)
52
+ *
53
+ * The server will verify the Sigstore bundle against the public Sigstore
54
+ * infrastructure (Rekor + Fulcio) before accepting.
55
+ *
56
+ * @param client - API client instance (must be authenticated)
57
+ * @param name - Tool name
58
+ * @param version - Tool version
59
+ * @param sigstoreBundle - Complete Sigstore bundle
60
+ * @returns Attestation response with verification result
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const result = await submitAttestation(client, "alice/utils/greeter", "1.2.0", {
65
+ * "$schema": "https://sigstore.dev/bundle/v1",
66
+ * "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
67
+ * "verificationMaterial": { ... },
68
+ * "messageSignature": { ... }
69
+ * });
70
+ *
71
+ * if (result.verification.verified) {
72
+ * console.log("Attestation verified and recorded!");
73
+ * }
74
+ * ```
75
+ */
76
+ export declare function submitAttestation(client: EnactApiClient, name: string, version: string, sigstoreBundle: Record<string, unknown>): Promise<{
77
+ auditor: string;
78
+ auditorProvider: string;
79
+ signedAt: Date;
80
+ rekorLogId: string;
81
+ rekorLogIndex?: number | undefined;
82
+ verification: {
83
+ verified: boolean;
84
+ verifiedAt: Date;
85
+ rekorVerified: boolean;
86
+ certificateVerified: boolean;
87
+ signatureVerified: boolean;
88
+ };
89
+ }>;
90
+ /**
91
+ * Revoke an attestation (v2)
92
+ *
93
+ * Only the original auditor can revoke their attestation.
94
+ *
95
+ * @param client - API client instance (must be authenticated)
96
+ * @param name - Tool name
97
+ * @param version - Tool version
98
+ * @param auditorEmail - Email of the auditor (from Sigstore certificate)
99
+ * @returns Revocation confirmation
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const result = await revokeAttestation(
104
+ * client,
105
+ * "alice/utils/greeter",
106
+ * "1.2.0",
107
+ * "security@example.com"
108
+ * );
109
+ * console.log(`Revoked at ${result.revokedAt}`);
110
+ * ```
111
+ */
112
+ export declare function revokeAttestation(client: EnactApiClient, name: string, version: string, auditorEmail: string): Promise<{
113
+ auditor: string;
114
+ revoked: true;
115
+ revokedAt: Date;
116
+ }>;
117
+ /**
118
+ * Check if a tool version has attestations from specific auditors
119
+ *
120
+ * @param client - API client instance
121
+ * @param name - Tool name
122
+ * @param version - Tool version
123
+ * @param trustedAuditors - List of trusted auditor emails
124
+ * @returns True if at least one trusted auditor has attested
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const isTrusted = await hasAttestation(
129
+ * client,
130
+ * "alice/utils/greeter",
131
+ * "1.2.0",
132
+ * ["security@example.com", "bob@github.com"]
133
+ * );
134
+ *
135
+ * if (isTrusted) {
136
+ * console.log("Tool is trusted!");
137
+ * }
138
+ * ```
139
+ */
140
+ export declare function hasAttestation(client: EnactApiClient, name: string, version: string, trustedAuditors: string[]): Promise<boolean>;
141
+ /**
142
+ * Get the full Sigstore bundle for a specific attestation
143
+ *
144
+ * This fetches the complete Sigstore bundle needed for local verification.
145
+ * Never trust the registry's verification status - always verify locally.
146
+ *
147
+ * @param client - API client instance
148
+ * @param name - Tool name
149
+ * @param version - Tool version
150
+ * @param auditor - Auditor email
151
+ * @returns Complete Sigstore bundle
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const bundle = await getAttestationBundle(
156
+ * client,
157
+ * "alice/utils/greeter",
158
+ * "1.2.0",
159
+ * "security@example.com"
160
+ * );
161
+ * ```
162
+ */
163
+ export declare function getAttestationBundle(client: EnactApiClient, name: string, version: string, auditor: string): Promise<SigstoreBundle>;
164
+ /**
165
+ * Verify an attestation locally using Sigstore (never trust registry)
166
+ *
167
+ * This performs cryptographic verification against Rekor transparency log,
168
+ * Fulcio certificate authority, and validates the signature. The registry's
169
+ * verification status is NEVER trusted - we always verify locally.
170
+ *
171
+ * @param client - API client instance
172
+ * @param name - Tool name
173
+ * @param version - Tool version
174
+ * @param attestation - Attestation metadata from registry
175
+ * @param bundleHash - Bundle hash to verify against (sha256:...)
176
+ * @returns True if attestation is cryptographically valid
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const attestations = await getAttestations(client, "alice/utils/greeter", "1.2.0");
181
+ * const attestation = attestations.attestations[0];
182
+ *
183
+ * const isValid = await verifyAttestationLocally(
184
+ * client,
185
+ * "alice/utils/greeter",
186
+ * "1.2.0",
187
+ * attestation,
188
+ * "sha256:abc123..."
189
+ * );
190
+ *
191
+ * if (isValid) {
192
+ * console.log("Attestation cryptographically verified!");
193
+ * }
194
+ * ```
195
+ */
196
+ export declare function verifyAttestationLocally(client: EnactApiClient, name: string, version: string, attestation: Attestation, bundleHash: string): Promise<boolean>;
197
+ /**
198
+ * Verify all attestations for a tool and return verified auditors
199
+ *
200
+ * This verifies all attestations locally and returns only those that pass
201
+ * cryptographic verification. Never trusts the registry's verification status.
202
+ *
203
+ * @param client - API client instance
204
+ * @param name - Tool name
205
+ * @param version - Tool version
206
+ * @param bundleHash - Bundle hash to verify against
207
+ * @returns Array of verified auditor emails
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * const verifiedAuditors = await verifyAllAttestations(
212
+ * client,
213
+ * "alice/utils/greeter",
214
+ * "1.2.0",
215
+ * "sha256:abc123..."
216
+ * );
217
+ *
218
+ * console.log(`Verified auditors: ${verifiedAuditors.join(", ")}`);
219
+ * ```
220
+ */
221
+ export declare function verifyAllAttestations(client: EnactApiClient, name: string, version: string, bundleHash: string): Promise<VerifiedAuditor[]>;
222
+ /**
223
+ * Check if a tool has a trusted attestation (with local verification)
224
+ *
225
+ * This checks if at least one attestation exists from a trusted auditor
226
+ * AND verifies it locally. Never trusts the registry's verification status.
227
+ *
228
+ * @param client - API client instance
229
+ * @param name - Tool name
230
+ * @param version - Tool version
231
+ * @param bundleHash - Bundle hash to verify against
232
+ * @param trustedAuditors - List of trusted auditor emails
233
+ * @returns True if at least one trusted auditor's attestation is verified
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const isTrusted = await hasTrustedAttestation(
238
+ * client,
239
+ * "alice/utils/greeter",
240
+ * "1.2.0",
241
+ * "sha256:abc123...",
242
+ * ["security@example.com", "bob@github.com"]
243
+ * );
244
+ *
245
+ * if (isTrusted) {
246
+ * console.log("Tool is trusted and verified!");
247
+ * } else {
248
+ * console.log("No trusted attestations found - use 'enact inspect' to review");
249
+ * }
250
+ * ```
251
+ */
252
+ export declare function hasTrustedAttestation(client: EnactApiClient, name: string, version: string, bundleHash: string, trustedAuditors: string[]): Promise<boolean>;
253
+ //# sourceMappingURL=attestations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestations.d.ts","sourceRoot":"","sources":["../src/attestations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAkD,MAAM,SAAS,CAAC;AAG3F;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;IACnC,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AACD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IACR,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GACA,OAAO,CAAC,uBAAuB,CAAC,CAgBlC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,IAAI,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,YAAY,EAAE;QACZ,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,EAAE,IAAI,CAAC;QACjB,aAAa,EAAE,OAAO,CAAC;QACvB,mBAAmB,EAAE,OAAO,CAAC;QAC7B,iBAAiB,EAAE,OAAO,CAAC;KAC5B,CAAC;CACH,CAAC,CAsBD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC,CAWD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAsBlB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,EAAE,CAAC,CA+D5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAQlB"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Attestation management (v2)
3
+ * Functions for managing auditor attestations
4
+ */
5
+ import { extractIdentityFromBundle, verifyBundle } from "@enactprotocol/trust";
6
+ import { emailToProviderIdentity } from "./utils";
7
+ /**
8
+ * Get all attestations for a tool version (v2)
9
+ *
10
+ * @param client - API client instance
11
+ * @param name - Tool name
12
+ * @param version - Tool version
13
+ * @param options - Pagination options
14
+ * @returns List of attestations with pagination info
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const result = await getAttestations(client, "alice/utils/greeter", "1.2.0", {
19
+ * limit: 10,
20
+ * offset: 0
21
+ * });
22
+ * console.log(`Found ${result.total} attestations`);
23
+ * ```
24
+ */
25
+ export async function getAttestations(client, name, version, options) {
26
+ const params = new URLSearchParams();
27
+ if (options?.limit !== undefined) {
28
+ params.set("limit", String(Math.min(options.limit, 100)));
29
+ }
30
+ if (options?.offset !== undefined) {
31
+ params.set("offset", String(options.offset));
32
+ }
33
+ const queryString = params.toString();
34
+ const path = `/tools/${name}/versions/${version}/attestations${queryString ? `?${queryString}` : ""}`;
35
+ const response = await client.get(path);
36
+ return response.data;
37
+ }
38
+ /**
39
+ * Submit an attestation for a tool version (v2)
40
+ *
41
+ * The server will verify the Sigstore bundle against the public Sigstore
42
+ * infrastructure (Rekor + Fulcio) before accepting.
43
+ *
44
+ * @param client - API client instance (must be authenticated)
45
+ * @param name - Tool name
46
+ * @param version - Tool version
47
+ * @param sigstoreBundle - Complete Sigstore bundle
48
+ * @returns Attestation response with verification result
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const result = await submitAttestation(client, "alice/utils/greeter", "1.2.0", {
53
+ * "$schema": "https://sigstore.dev/bundle/v1",
54
+ * "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
55
+ * "verificationMaterial": { ... },
56
+ * "messageSignature": { ... }
57
+ * });
58
+ *
59
+ * if (result.verification.verified) {
60
+ * console.log("Attestation verified and recorded!");
61
+ * }
62
+ * ```
63
+ */
64
+ export async function submitAttestation(client, name, version, sigstoreBundle) {
65
+ const response = await client.post(`/tools/${name}/versions/${version}/attestations`, {
66
+ bundle: sigstoreBundle,
67
+ });
68
+ return {
69
+ auditor: response.data.auditor,
70
+ auditorProvider: response.data.auditor_provider,
71
+ signedAt: new Date(response.data.signed_at),
72
+ rekorLogId: response.data.rekor_log_id,
73
+ rekorLogIndex: response.data.rekor_log_index,
74
+ verification: {
75
+ verified: response.data.verification.verified,
76
+ verifiedAt: new Date(response.data.verification.verified_at),
77
+ rekorVerified: response.data.verification.rekor_verified,
78
+ certificateVerified: response.data.verification.certificate_verified,
79
+ signatureVerified: response.data.verification.signature_verified,
80
+ },
81
+ };
82
+ }
83
+ /**
84
+ * Revoke an attestation (v2)
85
+ *
86
+ * Only the original auditor can revoke their attestation.
87
+ *
88
+ * @param client - API client instance (must be authenticated)
89
+ * @param name - Tool name
90
+ * @param version - Tool version
91
+ * @param auditorEmail - Email of the auditor (from Sigstore certificate)
92
+ * @returns Revocation confirmation
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * const result = await revokeAttestation(
97
+ * client,
98
+ * "alice/utils/greeter",
99
+ * "1.2.0",
100
+ * "security@example.com"
101
+ * );
102
+ * console.log(`Revoked at ${result.revokedAt}`);
103
+ * ```
104
+ */
105
+ export async function revokeAttestation(client, name, version, auditorEmail) {
106
+ const encodedEmail = encodeURIComponent(auditorEmail);
107
+ const response = await client.delete(`/tools/${name}/versions/${version}/attestations?auditor=${encodedEmail}`);
108
+ return {
109
+ auditor: response.data.auditor,
110
+ revoked: response.data.revoked,
111
+ revokedAt: new Date(response.data.revoked_at),
112
+ };
113
+ }
114
+ /**
115
+ * Check if a tool version has attestations from specific auditors
116
+ *
117
+ * @param client - API client instance
118
+ * @param name - Tool name
119
+ * @param version - Tool version
120
+ * @param trustedAuditors - List of trusted auditor emails
121
+ * @returns True if at least one trusted auditor has attested
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * const isTrusted = await hasAttestation(
126
+ * client,
127
+ * "alice/utils/greeter",
128
+ * "1.2.0",
129
+ * ["security@example.com", "bob@github.com"]
130
+ * );
131
+ *
132
+ * if (isTrusted) {
133
+ * console.log("Tool is trusted!");
134
+ * }
135
+ * ```
136
+ */
137
+ export async function hasAttestation(client, name, version, trustedAuditors) {
138
+ const result = await getAttestations(client, name, version);
139
+ return result.attestations.some((attestation) => trustedAuditors.includes(attestation.auditor) && attestation.verification?.verified === true);
140
+ }
141
+ /**
142
+ * Get the full Sigstore bundle for a specific attestation
143
+ *
144
+ * This fetches the complete Sigstore bundle needed for local verification.
145
+ * Never trust the registry's verification status - always verify locally.
146
+ *
147
+ * @param client - API client instance
148
+ * @param name - Tool name
149
+ * @param version - Tool version
150
+ * @param auditor - Auditor email
151
+ * @returns Complete Sigstore bundle
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const bundle = await getAttestationBundle(
156
+ * client,
157
+ * "alice/utils/greeter",
158
+ * "1.2.0",
159
+ * "security@example.com"
160
+ * );
161
+ * ```
162
+ */
163
+ export async function getAttestationBundle(client, name, version, auditor) {
164
+ const encodedAuditor = encodeURIComponent(auditor);
165
+ const response = await client.get(`/tools/${name}/versions/${version}/trust/attestations/${encodedAuditor}`);
166
+ return response.data;
167
+ }
168
+ /**
169
+ * Verify an attestation locally using Sigstore (never trust registry)
170
+ *
171
+ * This performs cryptographic verification against Rekor transparency log,
172
+ * Fulcio certificate authority, and validates the signature. The registry's
173
+ * verification status is NEVER trusted - we always verify locally.
174
+ *
175
+ * @param client - API client instance
176
+ * @param name - Tool name
177
+ * @param version - Tool version
178
+ * @param attestation - Attestation metadata from registry
179
+ * @param bundleHash - Bundle hash to verify against (sha256:...)
180
+ * @returns True if attestation is cryptographically valid
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * const attestations = await getAttestations(client, "alice/utils/greeter", "1.2.0");
185
+ * const attestation = attestations.attestations[0];
186
+ *
187
+ * const isValid = await verifyAttestationLocally(
188
+ * client,
189
+ * "alice/utils/greeter",
190
+ * "1.2.0",
191
+ * attestation,
192
+ * "sha256:abc123..."
193
+ * );
194
+ *
195
+ * if (isValid) {
196
+ * console.log("Attestation cryptographically verified!");
197
+ * }
198
+ * ```
199
+ */
200
+ export async function verifyAttestationLocally(client, name, version, attestation, bundleHash) {
201
+ try {
202
+ // Fetch the full Sigstore bundle from registry
203
+ const bundle = await getAttestationBundle(client, name, version, attestation.auditor);
204
+ // Convert bundle hash to Buffer for verification
205
+ const hashWithoutPrefix = bundleHash.replace("sha256:", "");
206
+ const artifactHash = Buffer.from(hashWithoutPrefix, "hex");
207
+ // Verify using @enactprotocol/trust package (checks Rekor, Fulcio, signatures)
208
+ const result = await verifyBundle(bundle, artifactHash, {
209
+ expectedIdentity: {
210
+ subjectAlternativeName: attestation.auditor,
211
+ },
212
+ });
213
+ return result.verified;
214
+ }
215
+ catch (error) {
216
+ // Verification failed - log error and return false
217
+ console.error(`Attestation verification failed for ${attestation.auditor}:`, error);
218
+ return false;
219
+ }
220
+ }
221
+ /**
222
+ * Verify all attestations for a tool and return verified auditors
223
+ *
224
+ * This verifies all attestations locally and returns only those that pass
225
+ * cryptographic verification. Never trusts the registry's verification status.
226
+ *
227
+ * @param client - API client instance
228
+ * @param name - Tool name
229
+ * @param version - Tool version
230
+ * @param bundleHash - Bundle hash to verify against
231
+ * @returns Array of verified auditor emails
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const verifiedAuditors = await verifyAllAttestations(
236
+ * client,
237
+ * "alice/utils/greeter",
238
+ * "1.2.0",
239
+ * "sha256:abc123..."
240
+ * );
241
+ *
242
+ * console.log(`Verified auditors: ${verifiedAuditors.join(", ")}`);
243
+ * ```
244
+ */
245
+ export async function verifyAllAttestations(client, name, version, bundleHash) {
246
+ const { attestations } = await getAttestations(client, name, version);
247
+ // Verify all attestations in parallel
248
+ const verificationResults = await Promise.all(attestations.map(async (attestation) => {
249
+ try {
250
+ // Fetch the full Sigstore bundle
251
+ const bundle = await getAttestationBundle(client, name, version, attestation.auditor);
252
+ // Convert bundle hash to Buffer for verification
253
+ const hashWithoutPrefix = bundleHash.replace("sha256:", "");
254
+ const artifactHash = Buffer.from(hashWithoutPrefix, "hex");
255
+ // Verify the bundle
256
+ const result = await verifyBundle(bundle, artifactHash, {
257
+ expectedIdentity: {
258
+ subjectAlternativeName: attestation.auditor,
259
+ },
260
+ });
261
+ if (result.verified) {
262
+ // Extract full identity from the verified bundle
263
+ const identity = extractIdentityFromBundle(bundle);
264
+ // Build provider:identity format using issuer info
265
+ const providerIdentity = emailToProviderIdentity(attestation.auditor, identity?.issuer, identity?.username);
266
+ return {
267
+ auditor: attestation.auditor,
268
+ identity,
269
+ providerIdentity,
270
+ isValid: true,
271
+ };
272
+ }
273
+ return { auditor: attestation.auditor, isValid: false };
274
+ }
275
+ catch {
276
+ return { auditor: attestation.auditor, isValid: false };
277
+ }
278
+ }));
279
+ // Return only verified auditors with full identity info
280
+ return verificationResults
281
+ .filter((result) => result.isValid)
282
+ .map((result) => ({
283
+ email: result.auditor,
284
+ identity: result.identity,
285
+ providerIdentity: result.providerIdentity,
286
+ }));
287
+ }
288
+ /**
289
+ * Check if a tool has a trusted attestation (with local verification)
290
+ *
291
+ * This checks if at least one attestation exists from a trusted auditor
292
+ * AND verifies it locally. Never trusts the registry's verification status.
293
+ *
294
+ * @param client - API client instance
295
+ * @param name - Tool name
296
+ * @param version - Tool version
297
+ * @param bundleHash - Bundle hash to verify against
298
+ * @param trustedAuditors - List of trusted auditor emails
299
+ * @returns True if at least one trusted auditor's attestation is verified
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * const isTrusted = await hasTrustedAttestation(
304
+ * client,
305
+ * "alice/utils/greeter",
306
+ * "1.2.0",
307
+ * "sha256:abc123...",
308
+ * ["security@example.com", "bob@github.com"]
309
+ * );
310
+ *
311
+ * if (isTrusted) {
312
+ * console.log("Tool is trusted and verified!");
313
+ * } else {
314
+ * console.log("No trusted attestations found - use 'enact inspect' to review");
315
+ * }
316
+ * ```
317
+ */
318
+ export async function hasTrustedAttestation(client, name, version, bundleHash, trustedAuditors) {
319
+ const verifiedAuditors = await verifyAllAttestations(client, name, version, bundleHash);
320
+ // Check if any verified auditor's providerIdentity matches a trusted auditor
321
+ // providerIdentity is in format "github:username" or "github:email@domain.com"
322
+ return verifiedAuditors.some((auditor) => {
323
+ return trustedAuditors.includes(auditor.providerIdentity);
324
+ });
325
+ }
326
+ //# sourceMappingURL=attestations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestations.js","sourceRoot":"","sources":["../src/attestations.ts"],"names":[],"mappings":"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"}