@effected/sbom 0.1.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/index.d.ts ADDED
@@ -0,0 +1,1034 @@
1
+ import { Brand, Context, Effect, FileSystem, Layer, Redacted, Result, Schema } from "effect";
2
+ import { Package } from "@effected/package-json";
3
+ import { Signer, Witness } from "@sigstore/sign";
4
+ //#region src/IdentityToken.d.ts
5
+ declare const IdentityTokenError_base: Schema.Class<IdentityTokenError, Schema.TaggedStruct<"IdentityTokenError", {
6
+ /** The audience the token was requested for. */
7
+ readonly audience: Schema.String;
8
+ /** The underlying failure, preserved structurally. */
9
+ readonly cause: Schema.Defect;
10
+ }>, import("effect/Cause").YieldableError>;
11
+ /**
12
+ * Raised when an identity token cannot be obtained.
13
+ *
14
+ * @remarks
15
+ * The audience is on the error because "which audience" is the first thing a
16
+ * caller checks when an exchange is refused — a token minted for the wrong one
17
+ * fails at the certificate authority, far from here.
18
+ *
19
+ * @public
20
+ */
21
+ declare class IdentityTokenError extends IdentityTokenError_base {
22
+ get message(): string;
23
+ }
24
+ /**
25
+ * The contract: one method, one audience, one redacted token.
26
+ *
27
+ * @remarks
28
+ * Deliberately smaller than any issuer's own surface. An implementation may
29
+ * cache, may decode claims, may do neither — none of that is this package's
30
+ * business, and a wider contract would make github-actions' issuer the only
31
+ * thing that could satisfy it.
32
+ *
33
+ * @public
34
+ */
35
+ interface IdentityTokenShape {
36
+ /** A workload identity token for `audience`. */
37
+ readonly token: (audience: string) => Effect.Effect<Redacted.Redacted<string>, IdentityTokenError>;
38
+ }
39
+ declare const IdentityToken_base: Context.ServiceClass<IdentityToken, "@effected/sbom/IdentityToken", IdentityTokenShape>;
40
+ /**
41
+ * A source of workload identity tokens.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { IdentityToken, SigstoreSigner } from "@effected/sbom";
46
+ * import { Layer } from "effect";
47
+ *
48
+ * const layer = SigstoreSigner.layer.pipe(Layer.provide(IdentityToken.layerStatic(token)));
49
+ * ```
50
+ *
51
+ * @public
52
+ */
53
+ declare class IdentityToken extends IdentityToken_base {
54
+ /**
55
+ * A layer answering with a token the caller already holds.
56
+ *
57
+ * @remarks
58
+ * For a consumer that obtained a token by some other route — a CI system
59
+ * that is not GitHub Actions, or a script that exchanged one itself. The
60
+ * audience is **ignored**, so it is the caller's job to have minted the token
61
+ * for the audience it will be used with; a layer cannot check that, and
62
+ * pretending otherwise would be theatre.
63
+ */
64
+ static readonly layerStatic: (token: Redacted.Redacted<string> | string) => Layer.Layer<IdentityToken>;
65
+ /**
66
+ * An in-memory double.
67
+ *
68
+ * @remarks
69
+ * Unlike {@link (SigstoreSigner:class).makeTest}, this one **answers** rather than
70
+ * dying: a fabricated OIDC token is a real answer to "give me a token" in a
71
+ * test, where a fabricated signature would be a lie about cryptography.
72
+ */
73
+ static readonly makeTest: (overrides?: Partial<IdentityTokenShape>) => IdentityTokenShape;
74
+ /** {@link (IdentityToken:class).makeTest} behind a `Layer`. */
75
+ static readonly layerTest: (overrides?: Partial<IdentityTokenShape>) => Layer.Layer<IdentityToken>;
76
+ }
77
+ //#endregion
78
+ //#region src/InTotoStatement.d.ts
79
+ /**
80
+ * The in-toto Statement v1 type URI, stamped onto every statement this package
81
+ * emits.
82
+ *
83
+ * @see {@link https://github.com/in-toto/attestation/blob/main/spec/v1/statement.md | in-toto Statement v1}
84
+ *
85
+ * @public
86
+ */
87
+ declare const IN_TOTO_STATEMENT_V1: "https://in-toto.io/Statement/v1";
88
+ /**
89
+ * The CycloneDX BOM predicate type, for attesting an SBOM.
90
+ *
91
+ * @public
92
+ */
93
+ declare const CYCLONEDX_BOM_PREDICATE: "https://cyclonedx.org/bom";
94
+ /**
95
+ * The URI naming what a statement asserts about its subjects.
96
+ *
97
+ * @remarks
98
+ * Deliberately an open string rather than a union: the predicate vocabulary is
99
+ * extensible by design, and a closed union here would refuse a valid statement
100
+ * for a predicate type this package has never heard of.
101
+ * {@link (SlsaProvenance:class).predicateType} and {@link CYCLONEDX_BOM_PREDICATE}
102
+ * are the two the kit produces.
103
+ *
104
+ * @public
105
+ */
106
+ type PredicateType = string;
107
+ declare const InvalidSha256DigestError_base: Schema.Class<InvalidSha256DigestError, Schema.TaggedStruct<"InvalidSha256DigestError", {
108
+ /** The offending input, preserved verbatim. */
109
+ readonly input: Schema.String;
110
+ }>, import("effect/Cause").YieldableError>;
111
+ /**
112
+ * Raised when a string is not a SHA-256 digest.
113
+ *
114
+ * @public
115
+ */
116
+ declare class InvalidSha256DigestError extends InvalidSha256DigestError_base {
117
+ get message(): string;
118
+ }
119
+ /**
120
+ * A SHA-256 digest as 64 lowercase hexadecimal characters, without an
121
+ * algorithm prefix.
122
+ *
123
+ * @remarks
124
+ * A deliberate small duplication rather than a shared package: `@effected/github`
125
+ * types the same value structurally on its attestation surface, and dragging a
126
+ * package across that seam to share one branded string would cost more than the
127
+ * duplication does. Recorded under the program's shared-vocabulary rule.
128
+ *
129
+ * @public
130
+ */
131
+ declare const Sha256Digest: Schema.brand<Schema.String, "Sha256Digest"> & {
132
+ isValid: (value: string) => boolean;
133
+ parseResult: (value: string) => Result.Result<Sha256Digest, InvalidSha256DigestError>;
134
+ parse: (value: string) => Effect.Effect<Sha256Digest, InvalidSha256DigestError, never>;
135
+ };
136
+ /**
137
+ * A SHA-256 digest as 64 lowercase hexadecimal characters.
138
+ *
139
+ * @public
140
+ */
141
+ type Sha256Digest = string & Brand.Brand<"Sha256Digest">;
142
+ declare const InTotoSubject_base: Schema.Class<InTotoSubject, Schema.Struct<{
143
+ /** How the subject is identified — a purl for an npm package. */
144
+ readonly name: Schema.String;
145
+ /** Algorithm to hex digest. */
146
+ readonly digest: Schema.$Record<Schema.String, Schema.String>;
147
+ }>, {}>;
148
+ /**
149
+ * A content-addressed artifact an attestation is about.
150
+ *
151
+ * @remarks
152
+ * `name` is conventionally a package URL (`pkg:npm/%40scope/name@1.0.0`), but
153
+ * the specification requires only that it be unique within the statement.
154
+ * `digest` is an open algorithm → hex map because in-toto permits several; this
155
+ * package writes `sha256`.
156
+ *
157
+ * @public
158
+ */
159
+ declare class InTotoSubject extends InTotoSubject_base {
160
+ /**
161
+ * A subject identified by a SHA-256 digest.
162
+ *
163
+ * @remarks
164
+ * **Total** — the digest is already validated, which is what
165
+ * {@link (Sha256Digest:variable).parseResult} is for.
166
+ */
167
+ static forSha256(name: string, digest: Sha256Digest): InTotoSubject;
168
+ }
169
+ /**
170
+ * Input to {@link (InTotoStatement:class).of}.
171
+ *
172
+ * @remarks
173
+ * The two predicate members are spelled out here and again on
174
+ * {@link InTotoSubjectInput} rather than shared through a base interface: an
175
+ * internal type named on a `@public` signature is a forgotten export, and a
176
+ * named alias is still a named symbol. Structural duplication is the only form
177
+ * the API gate accepts.
178
+ *
179
+ * @public
180
+ */
181
+ interface InTotoStatementInput {
182
+ /** The artifacts the statement is about. */
183
+ readonly subject: ReadonlyArray<InTotoSubject>;
184
+ /** What the statement asserts. */
185
+ readonly predicateType: PredicateType;
186
+ /** The assertion's body — a `SlsaProvenance`, a BOM, or a caller's own shape. */
187
+ readonly predicate: unknown;
188
+ }
189
+ /**
190
+ * Input to {@link (InTotoStatement:class).forSubject}.
191
+ *
192
+ * @remarks
193
+ * A record rather than positional arguments on purpose: `name` and
194
+ * `predicateType` are both strings, and a positional constructor invites a
195
+ * statement that silently attests the wrong thing.
196
+ *
197
+ * @public
198
+ */
199
+ interface InTotoSubjectInput {
200
+ /** How the single subject is identified. */
201
+ readonly name: string;
202
+ /** Its SHA-256 digest. */
203
+ readonly digest: Sha256Digest;
204
+ /** What the statement asserts. */
205
+ readonly predicateType: PredicateType;
206
+ /** The assertion's body — a `SlsaProvenance`, a BOM, or a caller's own shape. */
207
+ readonly predicate: unknown;
208
+ }
209
+ declare const InTotoStatement_base: Schema.Class<InTotoStatement, Schema.Struct<{
210
+ /** Always the in-toto Statement v1 URI. */
211
+ readonly _type: Schema.Literal<"https://in-toto.io/Statement/v1">;
212
+ /** The artifacts attested. */
213
+ readonly subject: Schema.$Array<typeof InTotoSubject>;
214
+ /** What is being asserted about them. */
215
+ readonly predicateType: Schema.String;
216
+ /** The assertion body. */
217
+ readonly predicate: Schema.Unknown;
218
+ }>, {}>;
219
+ /**
220
+ * An in-toto Statement v1.
221
+ *
222
+ * @remarks
223
+ * `predicate` is `unknown` by design — SLSA provenance, a CycloneDX BOM and a
224
+ * caller's own predicate all travel here, and the statement layer has no reason
225
+ * to introspect any of them.
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * import { InTotoStatement, Sha256Digest, SlsaProvenance } from "@effected/sbom";
230
+ *
231
+ * const statement = InTotoStatement.forSubject({
232
+ * name: "pkg:npm/%40scope/pkg@1.0.0",
233
+ * digest,
234
+ * predicateType: SlsaProvenance.predicateType,
235
+ * predicate: provenance,
236
+ * });
237
+ * ```
238
+ *
239
+ * @public
240
+ */
241
+ declare class InTotoStatement extends InTotoStatement_base {
242
+ /** A statement over any number of subjects. **Total.** */
243
+ static of(input: InTotoStatementInput): InTotoStatement;
244
+ /** A statement over a single artifact — the common case. **Total.** */
245
+ static forSubject(input: InTotoSubjectInput): InTotoStatement;
246
+ /**
247
+ * The statement as JSON — the bytes a DSSE envelope carries as its payload.
248
+ *
249
+ * @remarks
250
+ * Compact and in a fixed key order by default, so the same statement
251
+ * serializes to the same bytes on every run. Pass `space` for a form meant to
252
+ * be read by a person.
253
+ */
254
+ toJson(options?: {
255
+ readonly space?: number;
256
+ }): string;
257
+ }
258
+ //#endregion
259
+ //#region src/SbomDocument.d.ts
260
+ /**
261
+ * The CycloneDX component types this package emits.
262
+ *
263
+ * @remarks
264
+ * A deliberate subset of the specification's fourteen: an npm SBOM describes
265
+ * libraries and applications. The full enum is available in the schema; adding
266
+ * a member here is a one-line change when something needs one.
267
+ *
268
+ * @public
269
+ */
270
+ declare const ComponentType: Schema.Literals<readonly ["library", "application", "framework"]>;
271
+ /**
272
+ * The decoded type of {@link (ComponentType:variable)}.
273
+ *
274
+ * @public
275
+ */
276
+ type ComponentType = typeof ComponentType.Type;
277
+ /**
278
+ * An external reference's kind.
279
+ *
280
+ * @remarks
281
+ * The four the manifest mapping produces, out of the specification's 43. Each
282
+ * corresponds to a `package.json` field: `vcs` ← `repository`,
283
+ * `issue-tracker` ← `bugs`, `website` and `documentation` ← `homepage`.
284
+ *
285
+ * @public
286
+ */
287
+ declare const ExternalReferenceType: Schema.Literals<readonly ["vcs", "issue-tracker", "website", "documentation"]>;
288
+ /**
289
+ * The decoded type of {@link (ExternalReferenceType:variable)}.
290
+ *
291
+ * @public
292
+ */
293
+ type ExternalReferenceType = typeof ExternalReferenceType.Type;
294
+ declare const ExternalReference_base: Schema.Class<ExternalReference, Schema.Struct<{
295
+ /** The reference kind. */
296
+ readonly type: Schema.Literals<readonly ["vcs", "issue-tracker", "website", "documentation"]>;
297
+ /** The URL it points at, passed through exactly as supplied. */
298
+ readonly url: Schema.String;
299
+ }>, {}>;
300
+ /**
301
+ * A link from a component to something outside the BOM.
302
+ *
303
+ * @public
304
+ */
305
+ declare class ExternalReference extends ExternalReference_base {}
306
+ declare const Contact_base: Schema.Class<Contact, Schema.Struct<{
307
+ /** The contact's name. */
308
+ readonly name: Schema.optionalKey<Schema.String>;
309
+ /** Their email address. */
310
+ readonly email: Schema.optionalKey<Schema.String>;
311
+ /** Their telephone number. */
312
+ readonly phone: Schema.optionalKey<Schema.String>;
313
+ }>, {}>;
314
+ /**
315
+ * A point of contact — a person at a supplier, or an author of the BOM.
316
+ *
317
+ * @public
318
+ */
319
+ declare class Contact extends Contact_base {}
320
+ declare const Supplier_base: Schema.Class<Supplier, Schema.Struct<{
321
+ /** The supplier organization's name. */
322
+ readonly name: Schema.String;
323
+ /** Its URLs. */
324
+ readonly url: Schema.optionalKey<Schema.$Array<Schema.String>>;
325
+ /** Its points of contact. */
326
+ readonly contact: Schema.optionalKey<Schema.$Array<typeof Contact>>;
327
+ }>, {}>;
328
+ /**
329
+ * The organization that supplied a component.
330
+ *
331
+ * @remarks
332
+ * `name` is required because `metadata.supplier.name` is **NTIA minimum
333
+ * element 1**; a supplier without one satisfies nothing.
334
+ *
335
+ * @public
336
+ */
337
+ declare class Supplier extends Supplier_base {}
338
+ declare const Component_base: Schema.Class<Component, Schema.Struct<{
339
+ /** What kind of component this is. */
340
+ readonly type: Schema.Literals<readonly ["library", "application", "framework"]>;
341
+ /** The component's name — NTIA minimum element 2. */
342
+ readonly name: Schema.String;
343
+ /** Its version — NTIA minimum element 3. */
344
+ readonly version: Schema.optionalKey<Schema.String>;
345
+ /** The package URL uniquely identifying it — NTIA minimum element 4. */
346
+ readonly purl: Schema.optionalKey<Schema.String>;
347
+ /** The identifier other parts of the document reference it by. */
348
+ readonly bomRef: Schema.optionalKey<Schema.String>;
349
+ /** A short description. */
350
+ readonly description: Schema.optionalKey<Schema.String>;
351
+ /** SPDX license identifiers or expressions. */
352
+ readonly licenses: Schema.optionalKey<Schema.$Array<Schema.String>>;
353
+ /** Links out of the BOM. */
354
+ readonly externalReferences: Schema.optionalKey<Schema.$Array<typeof ExternalReference>>;
355
+ /** Discovery keywords — CycloneDX 1.6's `tags`, from the manifest's `keywords`. */
356
+ readonly tags: Schema.optionalKey<Schema.$Array<Schema.String>>;
357
+ /** The component's authors. */
358
+ readonly authors: Schema.optionalKey<Schema.$Array<typeof Contact>>;
359
+ /** The entity that published it. */
360
+ readonly publisher: Schema.optionalKey<Schema.String>;
361
+ /** A copyright statement. */
362
+ readonly copyright: Schema.optionalKey<Schema.String>;
363
+ }>, {}>;
364
+ /**
365
+ * One component in the BOM — the root, or a dependency.
366
+ *
367
+ * @remarks
368
+ * `bomRef` is spelled **`bom-ref`** in the emitted JSON; the rename happens in
369
+ * `Sbom.toJson`. Emitting `bomRef` produces a document that looks
370
+ * correct and validates wrong, which is why a test pins the key name.
371
+ *
372
+ * @public
373
+ */
374
+ declare class Component extends Component_base {}
375
+ declare const SbomMetadata_base: Schema.Class<SbomMetadata, Schema.Struct<{
376
+ /** When the BOM was assembled — NTIA minimum element 7. */
377
+ readonly timestamp: Schema.optionalKey<Schema.String>;
378
+ /** Who created the BOM — NTIA minimum element 6. */
379
+ readonly authors: Schema.optionalKey<Schema.$Array<typeof Contact>>;
380
+ /** The component the BOM describes. */
381
+ readonly component: Schema.optionalKey<typeof Component>;
382
+ /** Who supplied that component — NTIA minimum element 1. */
383
+ readonly supplier: Schema.optionalKey<typeof Supplier>;
384
+ }>, {}>;
385
+ /**
386
+ * Document-level metadata: who made the BOM, when, and about what.
387
+ *
388
+ * @public
389
+ */
390
+ declare class SbomMetadata extends SbomMetadata_base {}
391
+ declare const SbomDocument_base: Schema.Class<SbomDocument, Schema.Struct<{
392
+ /** Always `"CycloneDX"`. */
393
+ readonly bomFormat: Schema.Literal<"CycloneDX">;
394
+ /** Always `"1.6"`. */
395
+ readonly specVersion: Schema.Literal<"1.6">;
396
+ /** The document revision, `1` for a freshly assembled BOM. */
397
+ readonly version: Schema.Number;
398
+ /** Document metadata. */
399
+ readonly metadata: Schema.optionalKey<typeof SbomMetadata>;
400
+ /** The components the BOM describes, sorted by name. */
401
+ readonly components: Schema.$Array<typeof Component>;
402
+ }>, {}>;
403
+ /**
404
+ * A CycloneDX 1.6 bill of materials.
405
+ *
406
+ * @remarks
407
+ * Constructed by `Sbom.generate` and serialized by `Sbom.toJson`; both are
408
+ * total functions, because an owned model over validated values has nothing to
409
+ * fail at.
410
+ *
411
+ * @public
412
+ */
413
+ declare class SbomDocument extends SbomDocument_base {}
414
+ //#endregion
415
+ //#region src/NtiaReport.d.ts
416
+ /**
417
+ * The seven NTIA minimum elements, by stable identifier.
418
+ *
419
+ * @remarks
420
+ * A literal union rather than free text: this is what a consumer branches on,
421
+ * and a display name is what it renders afterwards.
422
+ *
423
+ * @public
424
+ */
425
+ declare const NtiaElementId: Schema.Literals<readonly ["supplierName", "componentName", "componentVersion", "uniqueIdentifier", "dependencyRelationship", "sbomAuthor", "timestamp"]>;
426
+ /**
427
+ * The decoded type of {@link (NtiaElementId:variable)}.
428
+ *
429
+ * @public
430
+ */
431
+ type NtiaElementId = typeof NtiaElementId.Type;
432
+ declare const NtiaElement_base: Schema.Class<NtiaElement, Schema.Struct<{
433
+ /** Which element this is. */
434
+ readonly id: Schema.Literals<readonly ["supplierName", "componentName", "componentVersion", "uniqueIdentifier", "dependencyRelationship", "sbomAuthor", "timestamp"]>;
435
+ /** Whether the document satisfies it. */
436
+ readonly satisfied: Schema.Boolean;
437
+ /** The value that satisfied it, when one did. */
438
+ readonly value: Schema.optionalKey<Schema.String>;
439
+ }>, {}>;
440
+ /**
441
+ * One element's verdict.
442
+ *
443
+ * @public
444
+ */
445
+ declare class NtiaElement extends NtiaElement_base {}
446
+ declare const NtiaReport_base: Schema.Class<NtiaReport, Schema.Struct<{
447
+ /** One verdict per element, in the published order. */
448
+ readonly elements: Schema.$Array<typeof NtiaElement>;
449
+ }>, {}>;
450
+ /**
451
+ * A document's standing against the NTIA minimum elements.
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * import { NtiaReport } from "@effected/sbom";
456
+ *
457
+ * const report = NtiaReport.of(document);
458
+ * if (!report.compliant) yield* Effect.logWarning(`SBOM missing: ${report.missing.join(", ")}`);
459
+ * ```
460
+ *
461
+ * @public
462
+ */
463
+ declare class NtiaReport extends NtiaReport_base {
464
+ /** Whether every element is satisfied. */
465
+ get compliant(): boolean;
466
+ /** The elements the document does not satisfy, by id. */
467
+ get missing(): ReadonlyArray<NtiaElementId>;
468
+ /**
469
+ * Check a document. **Total** — a report is the answer for every input,
470
+ * including a document that satisfies nothing.
471
+ */
472
+ static of(document: SbomDocument): NtiaReport;
473
+ }
474
+ //#endregion
475
+ //#region src/Sbom.d.ts
476
+ /**
477
+ * Input to {@link Sbom.generate}.
478
+ *
479
+ * @public
480
+ */
481
+ interface SbomInput {
482
+ /** The component the BOM is about. */
483
+ readonly root: Component;
484
+ /** Its dependencies, in any order — the document sorts them. */
485
+ readonly components: ReadonlyArray<Component>;
486
+ /** Document metadata. `root` is threaded onto it automatically. */
487
+ readonly metadata?: SbomMetadata;
488
+ }
489
+ /**
490
+ * Options for {@link Sbom.toJson}.
491
+ *
492
+ * @public
493
+ */
494
+ interface SbomJsonOptions {
495
+ /** `JSON.stringify` indentation. Defaults to `2`; `0` emits one line. */
496
+ readonly space?: number;
497
+ }
498
+ declare const SbomWriteError_base: Schema.Class<SbomWriteError, Schema.TaggedStruct<"SbomWriteError", {
499
+ /** The path that could not be written. */
500
+ readonly path: Schema.String;
501
+ /** The underlying failure, preserved structurally. */
502
+ readonly cause: Schema.Defect;
503
+ }>, import("effect/Cause").YieldableError>;
504
+ /**
505
+ * Raised when a BOM cannot be written to disk.
506
+ *
507
+ * @remarks
508
+ * The package's **only** error, and it is the filesystem's rather than the
509
+ * emitter's — assembling and serializing a document cannot fail.
510
+ *
511
+ * @public
512
+ */
513
+ declare class SbomWriteError extends SbomWriteError_base {
514
+ get message(): string;
515
+ }
516
+ /**
517
+ * The SBOM emitter: assemble, serialize, write.
518
+ *
519
+ * @example
520
+ * ```ts
521
+ * import { Sbom } from "@effected/sbom";
522
+ *
523
+ * const document = Sbom.generate({ root, components });
524
+ * const json = Sbom.toJson(document);
525
+ * ```
526
+ *
527
+ * @public
528
+ */
529
+ declare class Sbom {
530
+ private constructor();
531
+ /**
532
+ * Assemble a CycloneDX 1.6 document.
533
+ *
534
+ * @remarks
535
+ * **Total** — no error channel, because there is nothing here that can fail.
536
+ * Components are sorted by name so two runs over the same inputs produce the
537
+ * same bytes: an SBOM's digest becomes an attestation subject, and a document
538
+ * that reordered itself between runs would change that digest for no reason.
539
+ */
540
+ static readonly generate: (input: SbomInput) => SbomDocument;
541
+ /**
542
+ * Serialize a document to canonical CycloneDX 1.6 JSON.
543
+ *
544
+ * @remarks
545
+ * **Total.** Absent optional fields are omitted rather than emitted as `null`,
546
+ * and `bomRef` becomes the specification's hyphenated `bom-ref`.
547
+ */
548
+ static readonly toJson: (document: SbomDocument, options?: SbomJsonOptions) => string;
549
+ /**
550
+ * Write a document to `path` as canonical JSON.
551
+ *
552
+ * @remarks
553
+ * The one fallible member. It does not create parent directories — a caller
554
+ * that wants one creates it, so the failure mode stays "the path you gave me
555
+ * is not writable" rather than "something was created somewhere".
556
+ */
557
+ static readonly write: (document: SbomDocument, path: string, options?: SbomJsonOptions | undefined) => Effect.Effect<void, SbomWriteError, FileSystem.FileSystem>;
558
+ }
559
+ //#endregion
560
+ //#region src/SbomMetadataSource.d.ts
561
+ /**
562
+ * What a manifest cannot supply, and the two places an explicit value wins.
563
+ *
564
+ * @remarks
565
+ * A `package.json` says who wrote the software. It never says which
566
+ * organization supplied it, who assembled the BOM, or when — so `supplier`,
567
+ * `authors` and `timestamp` are explicit-only. Deriving them would fabricate
568
+ * three of the seven NTIA minimum elements.
569
+ *
570
+ * @public
571
+ */
572
+ interface SbomMetadataOptions {
573
+ /** The supplying organization — NTIA minimum element 1. */
574
+ readonly supplier?: Supplier;
575
+ /** Who assembled the BOM — NTIA minimum element 6. */
576
+ readonly authors?: ReadonlyArray<Contact>;
577
+ /** When it was assembled — NTIA minimum element 7, as an ISO 8601 string. */
578
+ readonly timestamp?: string;
579
+ /** The publishing entity. Falls back to the supplier, then the manifest's author. */
580
+ readonly publisher?: string;
581
+ /** A copyright statement; {@link SbomMetadataSource.formatCopyright} builds one. */
582
+ readonly copyright?: string;
583
+ /** The documentation URL, winning over the manifest's `homepage`. */
584
+ readonly documentationUrl?: string;
585
+ /** The root component's type. Defaults to `library`. */
586
+ readonly type?: ComponentType;
587
+ }
588
+ /**
589
+ * The fields a dependency contributes to its component entry.
590
+ *
591
+ * @public
592
+ */
593
+ interface ComponentInput {
594
+ /** The package name, scope included. */
595
+ readonly name: string;
596
+ /** Its resolved version. Absent produces a component with no version and no purl version segment. */
597
+ readonly version?: string;
598
+ /** An SPDX identifier or expression. */
599
+ readonly license?: string;
600
+ /** A short description. */
601
+ readonly description?: string;
602
+ /** The component type. Defaults to `library`. */
603
+ readonly type?: ComponentType;
604
+ }
605
+ /**
606
+ * The years a copyright statement spans.
607
+ *
608
+ * @public
609
+ */
610
+ interface CopyrightYears {
611
+ /** The first year of the range. Omit for a single-year statement. */
612
+ readonly startYear?: number;
613
+ /** The year the statement is current through — the caller's clock read, never ours. */
614
+ readonly year: number;
615
+ }
616
+ /**
617
+ * Derivation of CycloneDX metadata from a `package.json` manifest.
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * import { Sbom, SbomMetadataSource } from "@effected/sbom";
622
+ *
623
+ * const root = SbomMetadataSource.rootComponent(pkg, { supplier });
624
+ * const metadata = SbomMetadataSource.fromPackage(pkg, { supplier, timestamp });
625
+ * const document = Sbom.generate({ root, components, metadata });
626
+ * ```
627
+ *
628
+ * @public
629
+ */
630
+ declare class SbomMetadataSource {
631
+ private constructor();
632
+ /**
633
+ * The canonical npm package URL for a name and optional version.
634
+ *
635
+ * @remarks
636
+ * The NTIA's "unique identifier" element, and the identifier an in-toto
637
+ * subject names. Exposed because a caller assembling its own components —
638
+ * or a statement subject — needs the same encoding this module applies.
639
+ */
640
+ static readonly npmPurl: (name: string, version?: string) => string;
641
+ /**
642
+ * A component entry for one resolved dependency.
643
+ *
644
+ * @remarks
645
+ * The caller assembles the component list — the kit has no second merge
646
+ * rule for sibling packages released in the same wave, because which
647
+ * versions are in flight is release planning and `@effected/workspaces`
648
+ * already knows it. This is the mapping that would otherwise be
649
+ * re-derived at every call site.
650
+ */
651
+ static readonly componentFor: (input: ComponentInput) => Component;
652
+ /**
653
+ * The root component the BOM is about, derived from its own manifest.
654
+ *
655
+ * @remarks
656
+ * `publisher` resolves explicit → supplier name → the manifest's author,
657
+ * which is what lets NTIA element 6 be satisfied from a manifest alone.
658
+ */
659
+ static readonly rootComponent: (pkg: Package, options?: SbomMetadataOptions) => Component;
660
+ /**
661
+ * The manifest's outward links, as CycloneDX external references.
662
+ *
663
+ * @remarks
664
+ * Four of the specification's 43 types, one per manifest field: `vcs` ←
665
+ * `repository`, `issue-tracker` ← `bugs`, `documentation` ← `homepage`,
666
+ * `website` ← the supplier's first URL.
667
+ *
668
+ * A `repository` value the package-json model cannot interpret produces
669
+ * **no** reference rather than a passed-through string: CycloneDX's
670
+ * `externalReference.url` is a URL, and emitting `owner/name` there is a
671
+ * document that validates and misleads.
672
+ */
673
+ static readonly externalReferences: (pkg: Package, options?: SbomMetadataOptions) => ReadonlyArray<ExternalReference>;
674
+ /**
675
+ * Document-level metadata for a manifest.
676
+ *
677
+ * @remarks
678
+ * The root component is **not** on the returned value: `Sbom.generate`
679
+ * threads its `root` argument onto the metadata itself, so setting it
680
+ * here would only be overwritten. Build the root with
681
+ * {@link SbomMetadataSource.rootComponent} and pass both.
682
+ *
683
+ * When the caller supplies a supplier with no contacts, the manifest's
684
+ * maintainers fill them — the one derivation that crosses from manifest
685
+ * vocabulary into supplier vocabulary, and only where the caller left a
686
+ * hole.
687
+ */
688
+ static readonly fromPackage: (pkg: Package, options?: SbomMetadataOptions) => SbomMetadata;
689
+ /**
690
+ * A copyright statement for a holder and a year, or a span of years.
691
+ *
692
+ * @remarks
693
+ * The year is an **argument**. The predecessor defaulted it to
694
+ * `new Date().getFullYear()`, which made its output untestable and its
695
+ * purity a claim rather than a property; the ambient read belongs at the
696
+ * caller's edge.
697
+ */
698
+ static readonly formatCopyright: (holder: string, years: CopyrightYears) => string;
699
+ /**
700
+ * Field-wise metadata merge: every field the override carries wins.
701
+ *
702
+ * @remarks
703
+ * A helper, not a policy. Which side is the override — a config file over
704
+ * inferred values, or the reverse — is the consumer's precedence rule,
705
+ * and a library that decided it would be encoding one repository's
706
+ * release policy.
707
+ */
708
+ static readonly merge: (base: SbomMetadata, override: SbomMetadata) => SbomMetadata;
709
+ }
710
+ //#endregion
711
+ //#region src/SigstoreBundle.d.ts
712
+ /**
713
+ * The Sigstore bundle media type this package produces.
714
+ *
715
+ * @remarks
716
+ * v0.3 with a single certificate — what `DSSEBundleBuilder` emits by default,
717
+ * and what GitHub's `POST /repos/{owner}/{repo}/attestations` accepts.
718
+ *
719
+ * @public
720
+ */
721
+ declare const SIGSTORE_BUNDLE_V0_3_MEDIA_TYPE: "application/vnd.dev.sigstore.bundle.v0.3+json";
722
+ /**
723
+ * The DSSE payload type for an in-toto statement, per the GitHub attestations
724
+ * specification.
725
+ *
726
+ * @public
727
+ */
728
+ declare const IN_TOTO_PAYLOAD_TYPE: "application/vnd.in-toto+json";
729
+ declare const SigstoreBundle_base: Schema.Class<SigstoreBundle, Schema.Struct<{
730
+ /** The bundle's media type, usually {@link SIGSTORE_BUNDLE_V0_3_MEDIA_TYPE}. */
731
+ readonly mediaType: Schema.String;
732
+ /** The certificate and transparency-log entries a verifier checks. */
733
+ readonly verificationMaterial: Schema.Unknown;
734
+ /** The signed DSSE envelope carrying the statement. */
735
+ readonly dsseEnvelope: Schema.Unknown;
736
+ }>, {}>;
737
+ /**
738
+ * A signed Sigstore bundle: the wire form of an attestation.
739
+ *
740
+ * @remarks
741
+ * `verificationMaterial` and `dsseEnvelope` are `unknown` because their shapes
742
+ * belong to the Sigstore protobuf specifications, and re-declaring them here
743
+ * would be a second, drifting copy of a wire format we do not own. The bundle
744
+ * is opaque to everything that merely stores or forwards it.
745
+ *
746
+ * `mediaType` is carried through from what the builder produced rather than
747
+ * asserted — the version is the producer's statement about the bundle, and a
748
+ * literal here would quietly lie the day a builder emits a different one.
749
+ *
750
+ * @see {@link https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto | sigstore_bundle.proto}
751
+ *
752
+ * @public
753
+ */
754
+ declare class SigstoreBundle extends SigstoreBundle_base {}
755
+ //#endregion
756
+ //#region src/SigstoreSigner.d.ts
757
+ /**
758
+ * The OIDC audience Sigstore's certificate authority requires.
759
+ *
760
+ * @remarks
761
+ * It lives here, not at the call site, because it is the **signing protocol's**
762
+ * requirement rather than the caller's knowledge — which is why
763
+ * {@link SigstoreSignerShape.sign} takes only a statement and asks the identity
764
+ * contract for a token. Considered and rejected: `sign(statement, { token })`,
765
+ * which reads simpler and forces every caller to learn a constant that is none
766
+ * of its business.
767
+ *
768
+ * @public
769
+ */
770
+ declare const SIGSTORE_OIDC_AUDIENCE: "sigstore";
771
+ /**
772
+ * Which step of signing failed.
773
+ *
774
+ * @public
775
+ */
776
+ declare const SigningErrorKind: Schema.Literals<readonly ["identity", "certificate", "transparencyLog", "bundle"]>;
777
+ /**
778
+ * The decoded type of {@link (SigningErrorKind:variable)}.
779
+ *
780
+ * @public
781
+ */
782
+ type SigningErrorKind = typeof SigningErrorKind.Type;
783
+ declare const SigningError_base: Schema.Class<SigningError, Schema.TaggedStruct<"SigningError", {
784
+ /** Which step failed. */
785
+ readonly kind: Schema.Literals<readonly ["identity", "certificate", "transparencyLog", "bundle"]>;
786
+ /** The underlying failure, preserved structurally. */
787
+ readonly cause: Schema.Defect;
788
+ }>, import("effect/Cause").YieldableError>;
789
+ /**
790
+ * Raised when a statement cannot be signed.
791
+ *
792
+ * @remarks
793
+ * Sized to what a caller can act on: an `identity` failure is a workflow
794
+ * permissions problem, `certificate` is Fulcio, `transparencyLog` is Rekor, and
795
+ * `bundle` is everything else about assembling the result. The original failure
796
+ * is preserved structurally on `cause` rather than flattened into a message.
797
+ *
798
+ * @public
799
+ */
800
+ declare class SigningError extends SigningError_base {
801
+ get message(): string;
802
+ }
803
+ /**
804
+ * Where signing happens, and with what.
805
+ *
806
+ * @remarks
807
+ * The URL overrides exist for the Sigstore **staging** instance, which is what
808
+ * an opt-in end-to-end test points at. `signer` and `witnesses` replace the
809
+ * default Fulcio/Rekor pair outright — the seam that lets a test drive the
810
+ * **real** `DSSEBundleBuilder` with no network, no keys and no OIDC.
811
+ *
812
+ * @public
813
+ */
814
+ interface SigstoreSignerOptions {
815
+ /** Fulcio's base URL. Defaults to the public-good instance. */
816
+ readonly fulcioBaseUrl?: string;
817
+ /** Rekor's base URL. Defaults to the public-good instance. */
818
+ readonly rekorBaseUrl?: string;
819
+ /** Replace the certificate signer. */
820
+ readonly signer?: Signer;
821
+ /** Replace the witnesses. An empty array signs without a transparency log. */
822
+ readonly witnesses?: ReadonlyArray<Witness>;
823
+ }
824
+ /**
825
+ * The signing surface.
826
+ *
827
+ * @public
828
+ */
829
+ interface SigstoreSignerShape {
830
+ /**
831
+ * Sign a statement into a DSSE bundle.
832
+ *
833
+ * @remarks
834
+ * The identity token is fetched, used and discarded inside this call; it is
835
+ * `Redacted` from the contract to the moment it is handed to Fulcio, and
836
+ * declassified exactly once, here.
837
+ */
838
+ readonly sign: (statement: InTotoStatement) => Effect.Effect<SigstoreBundle, SigningError>;
839
+ }
840
+ declare const SigstoreSigner_base: Context.ServiceClass<SigstoreSigner, "@effected/sbom/SigstoreSigner", SigstoreSignerShape>;
841
+ /**
842
+ * Sigstore signing.
843
+ *
844
+ * @example
845
+ * ```ts
846
+ * import { IdentityToken, SigstoreSigner } from "@effected/sbom";
847
+ * import { Effect, Layer } from "effect";
848
+ *
849
+ * const program = Effect.gen(function* () {
850
+ * const signer = yield* SigstoreSigner;
851
+ * return yield* signer.sign(statement);
852
+ * });
853
+ * ```
854
+ *
855
+ * @public
856
+ */
857
+ declare class SigstoreSigner extends SigstoreSigner_base {
858
+ /** Signing against the public-good Fulcio and Rekor instances. */
859
+ static readonly layer: Layer.Layer<SigstoreSigner, never, IdentityToken>;
860
+ /** {@link (SigstoreSigner:class).layer} with the signing endpoints, or the signer and witnesses, replaced. */
861
+ static readonly layerWith: (options: SigstoreSignerOptions) => Layer.Layer<SigstoreSigner, never, IdentityToken>;
862
+ /**
863
+ * An in-memory double whose `sign` **dies** unless stubbed.
864
+ *
865
+ * @remarks
866
+ * The strongest case in the kit for the die-loudly default: no honest
867
+ * fabricated answer exists, because a bundle that looks signed and is not is
868
+ * exactly the failure an attestation exists to prevent. A test that wants a
869
+ * real bundle without a network drives the real builder through
870
+ * {@link (SigstoreSigner:class).layerWith}.
871
+ */
872
+ static readonly makeTest: (overrides?: Partial<SigstoreSignerShape>) => SigstoreSignerShape;
873
+ /** {@link (SigstoreSigner:class).makeTest} behind a `Layer`. */
874
+ static readonly layerTest: (overrides?: Partial<SigstoreSignerShape>) => Layer.Layer<SigstoreSigner>;
875
+ }
876
+ //#endregion
877
+ //#region src/SlsaProvenance.d.ts
878
+ /**
879
+ * The SLSA Provenance v1 predicate type URI.
880
+ *
881
+ * @public
882
+ */
883
+ declare const SLSA_PROVENANCE_V1: "https://slsa.dev/provenance/v1";
884
+ /**
885
+ * The SLSA build type identifying a GitHub Actions workflow build.
886
+ *
887
+ * @remarks
888
+ * A published **SLSA build-type identifier** — it names a provenance shape, not
889
+ * an Actions runtime detail — which is why it lives with the provenance model
890
+ * rather than in `@effected/github-actions`.
891
+ *
892
+ * @see {@link https://github.com/slsa-framework/github-actions-buildtypes/tree/main/workflow/v1 | workflow/v1}
893
+ *
894
+ * @public
895
+ */
896
+ declare const GITHUB_BUILD_TYPE: "https://actions.github.io/buildtypes/workflow/v1";
897
+ declare const SlsaBuildDefinition_base: Schema.Class<SlsaBuildDefinition, Schema.Struct<{
898
+ /** The build type URI — {@link GITHUB_BUILD_TYPE} for an Actions workflow. */
899
+ readonly buildType: Schema.String;
900
+ /** Parameters an external party controls: for Actions, the workflow itself. */
901
+ readonly externalParameters: Schema.Struct<{
902
+ /** The workflow the build ran. */
903
+ readonly workflow: Schema.Struct<{
904
+ /** The git ref the workflow ran on. */
905
+ readonly ref: Schema.String;
906
+ /** The repository's browsable URL. */
907
+ readonly repository: Schema.String;
908
+ /** The workflow file's path within the repository. */
909
+ readonly path: Schema.String;
910
+ }>;
911
+ }>;
912
+ /** Parameters the build platform controls. */
913
+ readonly internalParameters: Schema.Struct<{
914
+ /** The Actions-specific half, spelled in the claim names the platform uses. */
915
+ readonly github: Schema.Struct<{
916
+ /** The event that triggered the workflow. */
917
+ readonly event_name: Schema.String;
918
+ /** The repository's numeric id. */
919
+ readonly repository_id: Schema.String;
920
+ /** The repository owner's numeric id. */
921
+ readonly repository_owner_id: Schema.String;
922
+ /** `github-hosted` or `self-hosted`. */
923
+ readonly runner_environment: Schema.String;
924
+ }>;
925
+ }>;
926
+ /** The artifacts the build consumed — for Actions, the commit it built. */
927
+ readonly resolvedDependencies: Schema.$Array<Schema.Struct<{
928
+ /** A URI naming the dependency. */
929
+ readonly uri: Schema.String;
930
+ /** Algorithm to digest; `gitCommit` for a repository. */
931
+ readonly digest: Schema.$Record<Schema.String, Schema.String>;
932
+ }>>;
933
+ }>, {}>;
934
+ /**
935
+ * How the build was invoked, and what it was invoked from.
936
+ *
937
+ * @public
938
+ */
939
+ declare class SlsaBuildDefinition extends SlsaBuildDefinition_base {}
940
+ declare const SlsaRunDetails_base: Schema.Class<SlsaRunDetails, Schema.Struct<{
941
+ /** The build platform's identity. */
942
+ readonly builder: Schema.Struct<{
943
+ /** A URI identifying the builder — the reusable workflow, for Actions. */
944
+ readonly id: Schema.String;
945
+ }>;
946
+ /** Metadata about this particular run. */
947
+ readonly metadata: Schema.Struct<{
948
+ /** A URI locating the run that produced the artifact. */
949
+ readonly invocationId: Schema.String;
950
+ }>;
951
+ }>, {}>;
952
+ /**
953
+ * Who ran the build, and the record of that run.
954
+ *
955
+ * @public
956
+ */
957
+ declare class SlsaRunDetails extends SlsaRunDetails_base {}
958
+ /**
959
+ * The claims and runner facts a GitHub Actions provenance predicate is built
960
+ * from.
961
+ *
962
+ * @remarks
963
+ * A plain input record, **not** a service. There is nothing to swap and no IO
964
+ * to invert — it is the argument to a data constructor, and inventing a seam
965
+ * for one would repeat a mistake this program already reversed once.
966
+ *
967
+ * Fields are camelCase here and re-spelled to the platform's claim names where
968
+ * the predicate demands it, so a caller reads its own vocabulary and the
969
+ * emitted document keeps the specification's.
970
+ *
971
+ * @public
972
+ */
973
+ interface GitHubWorkflowProvenance {
974
+ /** The GitHub server's base URL — `https://github.com`, or a GHES host. */
975
+ readonly serverUrl: string;
976
+ /** `owner/repo`. */
977
+ readonly repository: string;
978
+ /** The git ref built. */
979
+ readonly ref: string;
980
+ /** The commit built. */
981
+ readonly sha: string;
982
+ /** The event that triggered the workflow. */
983
+ readonly eventName: string;
984
+ /** The workflow reference: `owner/repo/.github/workflows/x.yml@ref`. */
985
+ readonly workflowRef: string;
986
+ /** The job's workflow reference, which identifies the builder. */
987
+ readonly jobWorkflowRef: string;
988
+ /** The repository's numeric id. */
989
+ readonly repositoryId: string;
990
+ /** The repository owner's numeric id. */
991
+ readonly repositoryOwnerId: string;
992
+ /** `github-hosted` or `self-hosted`. */
993
+ readonly runnerEnvironment: string;
994
+ /** The workflow run's id. */
995
+ readonly runId: string;
996
+ /** Which attempt of that run this is. */
997
+ readonly runAttempt: string;
998
+ }
999
+ declare const SlsaProvenance_base: Schema.Class<SlsaProvenance, Schema.Struct<{
1000
+ /** What was built, and from what. */
1001
+ readonly buildDefinition: typeof SlsaBuildDefinition;
1002
+ /** Who built it, and when. */
1003
+ readonly runDetails: typeof SlsaRunDetails;
1004
+ }>, {}>;
1005
+ /**
1006
+ * A SLSA Provenance v1 predicate.
1007
+ *
1008
+ * @example
1009
+ * ```ts
1010
+ * import { SlsaProvenance } from "@effected/sbom";
1011
+ *
1012
+ * const provenance = SlsaProvenance.forGitHubWorkflow(claims);
1013
+ * ```
1014
+ *
1015
+ * @public
1016
+ */
1017
+ declare class SlsaProvenance extends SlsaProvenance_base {
1018
+ /** The predicate type URI a statement carrying this must declare. */
1019
+ static readonly predicateType: PredicateType;
1020
+ /** The build type this package's GitHub-workflow constructor stamps. */
1021
+ static readonly buildType: string;
1022
+ /**
1023
+ * Provenance for a GitHub Actions `workflow/v1` build.
1024
+ *
1025
+ * @remarks
1026
+ * **Total** — a pure projection of its argument. Every value it needs is
1027
+ * already in the input; nothing is read from the environment and nothing can
1028
+ * fail.
1029
+ */
1030
+ static forGitHubWorkflow(input: GitHubWorkflowProvenance): SlsaProvenance;
1031
+ }
1032
+ //#endregion
1033
+ export { CYCLONEDX_BOM_PREDICATE, Component, type ComponentInput, ComponentType, Contact, type CopyrightYears, ExternalReference, ExternalReferenceType, GITHUB_BUILD_TYPE, type GitHubWorkflowProvenance, IN_TOTO_PAYLOAD_TYPE, IN_TOTO_STATEMENT_V1, IdentityToken, IdentityTokenError, type IdentityTokenShape, InTotoStatement, type InTotoStatementInput, InTotoSubject, type InTotoSubjectInput, InvalidSha256DigestError, NtiaElement, NtiaElementId, NtiaReport, type PredicateType, SIGSTORE_BUNDLE_V0_3_MEDIA_TYPE, SIGSTORE_OIDC_AUDIENCE, SLSA_PROVENANCE_V1, Sbom, SbomDocument, type SbomInput, type SbomJsonOptions, SbomMetadata, type SbomMetadataOptions, SbomMetadataSource, SbomWriteError, Sha256Digest, SigningError, SigningErrorKind, SigstoreBundle, SigstoreSigner, type SigstoreSignerOptions, type SigstoreSignerShape, SlsaBuildDefinition, SlsaProvenance, SlsaRunDetails, Supplier };
1034
+ //# sourceMappingURL=index.d.ts.map