@actions/attest 1.0.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/LICENSE.md +9 -0
- package/README.md +172 -0
- package/lib/attest.d.ts +22 -0
- package/lib/attest.js +79 -0
- package/lib/attest.js.map +1 -0
- package/lib/endpoints.d.ts +12 -0
- package/lib/endpoints.js +64 -0
- package/lib/endpoints.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/lib/intoto.d.ts +18 -0
- package/lib/intoto.js +20 -0
- package/lib/intoto.js.map +1 -0
- package/lib/provenance.d.ts +27 -0
- package/lib/provenance.js +89 -0
- package/lib/provenance.js.map +1 -0
- package/lib/shared.types.d.ts +15 -0
- package/lib/shared.types.js +3 -0
- package/lib/shared.types.js.map +1 -0
- package/lib/sign.d.ts +43 -0
- package/lib/sign.js +62 -0
- package/lib/sign.js.map +1 -0
- package/lib/store.d.ts +8 -0
- package/lib/store.js +66 -0
- package/lib/store.js.map +1 -0
- package/package.json +49 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright 2024 GitHub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# `@actions/attest`
|
|
2
|
+
|
|
3
|
+
Functions for generating signed attestations for workflow artifacts.
|
|
4
|
+
|
|
5
|
+
Attestations bind some subject (a named artifact along with its digest) to a
|
|
6
|
+
predicate (some assertion about that subject) using the [in-toto
|
|
7
|
+
statement](https://github.com/in-toto/attestation/tree/main/spec/v1) format. A
|
|
8
|
+
signature is generated for the attestation using a
|
|
9
|
+
[Sigstore](https://www.sigstore.dev/)-issued signing certificate.
|
|
10
|
+
|
|
11
|
+
Once the attestation has been created and signed, it will be uploaded to the GH
|
|
12
|
+
attestations API and associated with the repository from which the workflow was
|
|
13
|
+
initiated.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### `attest`
|
|
18
|
+
|
|
19
|
+
The `attest` function takes the supplied subject/predicate pair and generates a
|
|
20
|
+
signed attestation.
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const { attest } = require('@actions/attest');
|
|
24
|
+
const core = require('@actions/core');
|
|
25
|
+
|
|
26
|
+
async function run() {
|
|
27
|
+
// In order to persist attestations to the repo, this should be a token with
|
|
28
|
+
// repository write permissions.
|
|
29
|
+
const ghToken = core.getInput('gh-token');
|
|
30
|
+
|
|
31
|
+
const attestation = await attest({
|
|
32
|
+
subjectName: 'my-artifact-name',
|
|
33
|
+
subjectDigest: { 'sha256': '36ab4667...'},
|
|
34
|
+
predicateType: 'https://in-toto.io/attestation/release',
|
|
35
|
+
predicate: { . . . },
|
|
36
|
+
token: ghToken
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(attestation);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
run();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The `attest` function supports the following options:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
export type AttestOptions = {
|
|
49
|
+
// The name of the subject to be attested.
|
|
50
|
+
subjectName: string
|
|
51
|
+
// The digest of the subject to be attested. Should be a map of digest
|
|
52
|
+
// algorithms to their hex-encoded values.
|
|
53
|
+
subjectDigest: Record<string, string>
|
|
54
|
+
// URI identifying the content type of the predicate being attested.
|
|
55
|
+
predicateType: string
|
|
56
|
+
// Predicate to be attested.
|
|
57
|
+
predicate: object
|
|
58
|
+
// GitHub token for writing attestations.
|
|
59
|
+
token: string
|
|
60
|
+
// Sigstore instance to use for signing. Must be one of "public-good" or
|
|
61
|
+
// "github".
|
|
62
|
+
sigstore?: 'public-good' | 'github'
|
|
63
|
+
// Whether to skip writing the attestation to the GH attestations API.
|
|
64
|
+
skipWrite?: boolean
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `attestProvenance`
|
|
69
|
+
|
|
70
|
+
The `attestProvenance` function accepts the name and digest of some artifact and
|
|
71
|
+
generates a build provenance attestation over those values.
|
|
72
|
+
|
|
73
|
+
The attestation is formed by first generating a [SLSA provenance
|
|
74
|
+
predicate](https://slsa.dev/spec/v1.0/provenance) populated with
|
|
75
|
+
[metadata](https://github.com/slsa-framework/github-actions-buildtypes/tree/main/workflow/v1)
|
|
76
|
+
pulled from the GitHub Actions run.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const { attestProvenance } = require('@actions/attest');
|
|
80
|
+
const core = require('@actions/core');
|
|
81
|
+
|
|
82
|
+
async function run() {
|
|
83
|
+
// In order to persist attestations to the repo, this should be a token with
|
|
84
|
+
// repository write permissions.
|
|
85
|
+
const ghToken = core.getInput('gh-token');
|
|
86
|
+
|
|
87
|
+
const attestation = await attestProvenance({
|
|
88
|
+
subjectName: 'my-artifact-name',
|
|
89
|
+
subjectDigest: { 'sha256': '36ab4667...'},
|
|
90
|
+
token: ghToken
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
console.log(attestation);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
run();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The `attestProvenance` function supports the following options:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
export type AttestProvenanceOptions = {
|
|
103
|
+
// The name of the subject to be attested.
|
|
104
|
+
subjectName: string
|
|
105
|
+
// The digest of the subject to be attested. Should be a map of digest
|
|
106
|
+
// algorithms to their hex-encoded values.
|
|
107
|
+
subjectDigest: Record<string, string>
|
|
108
|
+
// GitHub token for writing attestations.
|
|
109
|
+
token: string
|
|
110
|
+
// Sigstore instance to use for signing. Must be one of "public-good" or
|
|
111
|
+
// "github".
|
|
112
|
+
sigstore?: 'public-good' | 'github'
|
|
113
|
+
// Whether to skip writing the attestation to the GH attestations API.
|
|
114
|
+
skipWrite?: boolean
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `Attestation`
|
|
119
|
+
|
|
120
|
+
The `Attestation` returned by `attest`/`attestProvenance` has the following
|
|
121
|
+
fields:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
export type Attestation = {
|
|
125
|
+
/*
|
|
126
|
+
* JSON-serialized Sigstore bundle containing the provenance attestation,
|
|
127
|
+
* signature, signing certificate and witnessed timestamp.
|
|
128
|
+
*/
|
|
129
|
+
bundle: SerializedBundle
|
|
130
|
+
/*
|
|
131
|
+
* PEM-encoded signing certificate used to sign the attestation.
|
|
132
|
+
*/
|
|
133
|
+
certificate: string
|
|
134
|
+
/*
|
|
135
|
+
* ID of Rekor transparency log entry created for the attestation (if
|
|
136
|
+
* applicable).
|
|
137
|
+
*/
|
|
138
|
+
tlogID?: string
|
|
139
|
+
/*
|
|
140
|
+
* ID of the persisted attestation (accessible via the GH API).
|
|
141
|
+
*/
|
|
142
|
+
attestationID?: string
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
For details about the Sigstore bundle format, see the [Bundle protobuf
|
|
147
|
+
specification](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto).
|
|
148
|
+
|
|
149
|
+
## Sigstore Instance
|
|
150
|
+
|
|
151
|
+
When generating the signed attestation there are two different Sigstore
|
|
152
|
+
instances which can be used to issue the signing certificate. By default,
|
|
153
|
+
workflows initiated from public repositories will use the Sigstore public-good
|
|
154
|
+
instance and persist the attestation signature to the public [Rekor transparency
|
|
155
|
+
log](https://docs.sigstore.dev/logging/overview/). Workflows initiated from
|
|
156
|
+
private/internal repositories will use the GitHub-internal Sigstore instance
|
|
157
|
+
which uses a signed timestamp issued by GitHub's timestamp authority in place of
|
|
158
|
+
the public transparency log.
|
|
159
|
+
|
|
160
|
+
The default Sigstore instance selection can be overridden by passing an explicit
|
|
161
|
+
value of either "public-good" or "github" for the `sigstore` option when calling
|
|
162
|
+
either `attest` or `attestProvenance`.
|
|
163
|
+
|
|
164
|
+
## Storage
|
|
165
|
+
|
|
166
|
+
Attestations created by `attest`/`attestProvenance` will be uploaded to the GH
|
|
167
|
+
attestations API and associated with the appropriate repository. Attestation
|
|
168
|
+
storage is only supported for public repositories or repositories which belong
|
|
169
|
+
to a GitHub Enterprise Cloud account.
|
|
170
|
+
|
|
171
|
+
In order to generate attestations for private, non-Enterprise repositories, the
|
|
172
|
+
`skipWrite` option should be set to `true`.
|
package/lib/attest.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SigstoreInstance } from './endpoints';
|
|
2
|
+
import type { Attestation } from './shared.types';
|
|
3
|
+
/**
|
|
4
|
+
* Options for attesting a subject / predicate.
|
|
5
|
+
*/
|
|
6
|
+
export type AttestOptions = {
|
|
7
|
+
subjectName: string;
|
|
8
|
+
subjectDigest: Record<string, string>;
|
|
9
|
+
predicateType: string;
|
|
10
|
+
predicate: object;
|
|
11
|
+
token: string;
|
|
12
|
+
sigstore?: SigstoreInstance;
|
|
13
|
+
skipWrite?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Generates an attestation for the given subject and predicate. The subject and
|
|
17
|
+
* predicate are combined into an in-toto statement, which is then signed using
|
|
18
|
+
* the identified Sigstore instance and stored as an attestation.
|
|
19
|
+
* @param options - The options for attestation.
|
|
20
|
+
* @returns A promise that resolves to the attestation.
|
|
21
|
+
*/
|
|
22
|
+
export declare function attest(options: AttestOptions): Promise<Attestation>;
|
package/lib/attest.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.attest = void 0;
|
|
13
|
+
const bundle_1 = require("@sigstore/bundle");
|
|
14
|
+
const crypto_1 = require("crypto");
|
|
15
|
+
const endpoints_1 = require("./endpoints");
|
|
16
|
+
const intoto_1 = require("./intoto");
|
|
17
|
+
const sign_1 = require("./sign");
|
|
18
|
+
const store_1 = require("./store");
|
|
19
|
+
const INTOTO_PAYLOAD_TYPE = 'application/vnd.in-toto+json';
|
|
20
|
+
/**
|
|
21
|
+
* Generates an attestation for the given subject and predicate. The subject and
|
|
22
|
+
* predicate are combined into an in-toto statement, which is then signed using
|
|
23
|
+
* the identified Sigstore instance and stored as an attestation.
|
|
24
|
+
* @param options - The options for attestation.
|
|
25
|
+
* @returns A promise that resolves to the attestation.
|
|
26
|
+
*/
|
|
27
|
+
function attest(options) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const subject = {
|
|
30
|
+
name: options.subjectName,
|
|
31
|
+
digest: options.subjectDigest
|
|
32
|
+
};
|
|
33
|
+
const predicate = {
|
|
34
|
+
type: options.predicateType,
|
|
35
|
+
params: options.predicate
|
|
36
|
+
};
|
|
37
|
+
const statement = (0, intoto_1.buildIntotoStatement)(subject, predicate);
|
|
38
|
+
// Sign the provenance statement
|
|
39
|
+
const payload = {
|
|
40
|
+
body: Buffer.from(JSON.stringify(statement)),
|
|
41
|
+
type: INTOTO_PAYLOAD_TYPE
|
|
42
|
+
};
|
|
43
|
+
const endpoints = (0, endpoints_1.signingEndpoints)(options.sigstore);
|
|
44
|
+
const bundle = yield (0, sign_1.signPayload)(payload, endpoints);
|
|
45
|
+
// Store the attestation
|
|
46
|
+
let attestationID;
|
|
47
|
+
if (options.skipWrite !== true) {
|
|
48
|
+
attestationID = yield (0, store_1.writeAttestation)((0, bundle_1.bundleToJSON)(bundle), options.token);
|
|
49
|
+
}
|
|
50
|
+
return toAttestation(bundle, attestationID);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.attest = attest;
|
|
54
|
+
function toAttestation(bundle, attestationID) {
|
|
55
|
+
let certBytes;
|
|
56
|
+
switch (bundle.verificationMaterial.content.$case) {
|
|
57
|
+
case 'x509CertificateChain':
|
|
58
|
+
certBytes =
|
|
59
|
+
bundle.verificationMaterial.content.x509CertificateChain.certificates[0]
|
|
60
|
+
.rawBytes;
|
|
61
|
+
break;
|
|
62
|
+
case 'certificate':
|
|
63
|
+
certBytes = bundle.verificationMaterial.content.certificate.rawBytes;
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
throw new Error('Bundle must contain an x509 certificate');
|
|
67
|
+
}
|
|
68
|
+
const signingCert = new crypto_1.X509Certificate(certBytes);
|
|
69
|
+
// Collect transparency log ID if available
|
|
70
|
+
const tlogEntries = bundle.verificationMaterial.tlogEntries;
|
|
71
|
+
const tlogID = tlogEntries.length > 0 ? tlogEntries[0].logIndex : undefined;
|
|
72
|
+
return {
|
|
73
|
+
bundle: (0, bundle_1.bundleToJSON)(bundle),
|
|
74
|
+
certificate: signingCert.toString(),
|
|
75
|
+
tlogID,
|
|
76
|
+
attestationID
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=attest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attest.js","sourceRoot":"","sources":["../src/attest.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAqD;AACrD,mCAAsC;AACtC,2CAA8D;AAC9D,qCAA6C;AAC7C,iCAA2C;AAC3C,mCAAwC;AAIxC,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAwB1D;;;;;;GAMG;AACH,SAAsB,MAAM,CAAC,OAAsB;;QACjD,MAAM,OAAO,GAAY;YACvB,IAAI,EAAE,OAAO,CAAC,WAAW;YACzB,MAAM,EAAE,OAAO,CAAC,aAAa;SAC9B,CAAA;QACD,MAAM,SAAS,GAAc;YAC3B,IAAI,EAAE,OAAO,CAAC,aAAa;YAC3B,MAAM,EAAE,OAAO,CAAC,SAAS;SAC1B,CAAA;QACD,MAAM,SAAS,GAAG,IAAA,6BAAoB,EAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAE1D,gCAAgC;QAChC,MAAM,OAAO,GAAY;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAC5C,IAAI,EAAE,mBAAmB;SAC1B,CAAA;QACD,MAAM,SAAS,GAAG,IAAA,4BAAgB,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACpD,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAW,EAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAEpD,wBAAwB;QACxB,IAAI,aAAiC,CAAA;QACrC,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,EAAE;YAC9B,aAAa,GAAG,MAAM,IAAA,wBAAgB,EAAC,IAAA,qBAAY,EAAC,MAAM,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;SAC5E;QAED,OAAO,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC7C,CAAC;CAAA;AA1BD,wBA0BC;AAED,SAAS,aAAa,CAAC,MAAc,EAAE,aAAsB;IAC3D,IAAI,SAAiB,CAAA;IACrB,QAAQ,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,EAAE;QACjD,KAAK,sBAAsB;YACzB,SAAS;gBACP,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC,CAAC;qBACrE,QAAQ,CAAA;YACb,MAAK;QACP,KAAK,aAAa;YAChB,SAAS,GAAG,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAA;YACpE,MAAK;QACP;YACE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;KAC7D;IAED,MAAM,WAAW,GAAG,IAAI,wBAAe,CAAC,SAAS,CAAC,CAAA;IAElD,2CAA2C;IAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,oBAAoB,CAAC,WAAW,CAAA;IAC3D,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAE3E,OAAO;QACL,MAAM,EAAE,IAAA,qBAAY,EAAC,MAAM,CAAC;QAC5B,WAAW,EAAE,WAAW,CAAC,QAAQ,EAAE;QACnC,MAAM;QACN,aAAa;KACd,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const PUBLIC_GOOD_ID = "public-good";
|
|
2
|
+
declare const GITHUB_ID = "github";
|
|
3
|
+
export type SigstoreInstance = typeof PUBLIC_GOOD_ID | typeof GITHUB_ID;
|
|
4
|
+
export type Endpoints = {
|
|
5
|
+
fulcioURL: string;
|
|
6
|
+
rekorURL?: string;
|
|
7
|
+
tsaServerURL?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const SIGSTORE_PUBLIC_GOOD: Endpoints;
|
|
10
|
+
export declare const SIGSTORE_GITHUB: Endpoints;
|
|
11
|
+
export declare const signingEndpoints: (sigstore?: SigstoreInstance) => Endpoints;
|
|
12
|
+
export {};
|
package/lib/endpoints.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.signingEndpoints = exports.SIGSTORE_GITHUB = exports.SIGSTORE_PUBLIC_GOOD = void 0;
|
|
27
|
+
const github = __importStar(require("@actions/github"));
|
|
28
|
+
const PUBLIC_GOOD_ID = 'public-good';
|
|
29
|
+
const GITHUB_ID = 'github';
|
|
30
|
+
const FULCIO_PUBLIC_GOOD_URL = 'https://fulcio.sigstore.dev';
|
|
31
|
+
const REKOR_PUBLIC_GOOD_URL = 'https://rekor.sigstore.dev';
|
|
32
|
+
const FULCIO_INTERNAL_URL = 'https://fulcio.githubapp.com';
|
|
33
|
+
const TSA_INTERNAL_URL = 'https://timestamp.githubapp.com';
|
|
34
|
+
exports.SIGSTORE_PUBLIC_GOOD = {
|
|
35
|
+
fulcioURL: FULCIO_PUBLIC_GOOD_URL,
|
|
36
|
+
rekorURL: REKOR_PUBLIC_GOOD_URL
|
|
37
|
+
};
|
|
38
|
+
exports.SIGSTORE_GITHUB = {
|
|
39
|
+
fulcioURL: FULCIO_INTERNAL_URL,
|
|
40
|
+
tsaServerURL: TSA_INTERNAL_URL
|
|
41
|
+
};
|
|
42
|
+
const signingEndpoints = (sigstore) => {
|
|
43
|
+
var _a;
|
|
44
|
+
let instance;
|
|
45
|
+
// An explicitly set instance type takes precedence, but if not set, use the
|
|
46
|
+
// repository's visibility to determine the instance type.
|
|
47
|
+
if (sigstore && [PUBLIC_GOOD_ID, GITHUB_ID].includes(sigstore)) {
|
|
48
|
+
instance = sigstore;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
instance =
|
|
52
|
+
((_a = github.context.payload.repository) === null || _a === void 0 ? void 0 : _a.visibility) === 'public'
|
|
53
|
+
? PUBLIC_GOOD_ID
|
|
54
|
+
: GITHUB_ID;
|
|
55
|
+
}
|
|
56
|
+
switch (instance) {
|
|
57
|
+
case PUBLIC_GOOD_ID:
|
|
58
|
+
return exports.SIGSTORE_PUBLIC_GOOD;
|
|
59
|
+
case GITHUB_ID:
|
|
60
|
+
return exports.SIGSTORE_GITHUB;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.signingEndpoints = signingEndpoints;
|
|
64
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wDAAyC;AAEzC,MAAM,cAAc,GAAG,aAAa,CAAA;AACpC,MAAM,SAAS,GAAG,QAAQ,CAAA;AAE1B,MAAM,sBAAsB,GAAG,6BAA6B,CAAA;AAC5D,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAE1D,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAC1D,MAAM,gBAAgB,GAAG,iCAAiC,CAAA;AAU7C,QAAA,oBAAoB,GAAc;IAC7C,SAAS,EAAE,sBAAsB;IACjC,QAAQ,EAAE,qBAAqB;CAChC,CAAA;AAEY,QAAA,eAAe,GAAc;IACxC,SAAS,EAAE,mBAAmB;IAC9B,YAAY,EAAE,gBAAgB;CAC/B,CAAA;AAEM,MAAM,gBAAgB,GAAG,CAAC,QAA2B,EAAa,EAAE;;IACzE,IAAI,QAA0B,CAAA;IAE9B,4EAA4E;IAC5E,0DAA0D;IAC1D,IAAI,QAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAC9D,QAAQ,GAAG,QAAQ,CAAA;KACpB;SAAM;QACL,QAAQ;YACN,CAAA,MAAA,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,0CAAE,UAAU,MAAK,QAAQ;gBACxD,CAAC,CAAC,cAAc;gBAChB,CAAC,CAAC,SAAS,CAAA;KAChB;IAED,QAAQ,QAAQ,EAAE;QAChB,KAAK,cAAc;YACjB,OAAO,4BAAoB,CAAA;QAC7B,KAAK,SAAS;YACZ,OAAO,uBAAe,CAAA;KACzB;AACH,CAAC,CAAA;AApBY,QAAA,gBAAgB,oBAoB5B"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AttestOptions, attest } from './attest';
|
|
2
|
+
export { AttestProvenanceOptions, attestProvenance, buildSLSAProvenancePredicate } from './provenance';
|
|
3
|
+
export type { SerializedBundle } from '@sigstore/bundle';
|
|
4
|
+
export type { Attestation, Predicate, Subject } from './shared.types';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSLSAProvenancePredicate = exports.attestProvenance = exports.attest = void 0;
|
|
4
|
+
var attest_1 = require("./attest");
|
|
5
|
+
Object.defineProperty(exports, "attest", { enumerable: true, get: function () { return attest_1.attest; } });
|
|
6
|
+
var provenance_1 = require("./provenance");
|
|
7
|
+
Object.defineProperty(exports, "attestProvenance", { enumerable: true, get: function () { return provenance_1.attestProvenance; } });
|
|
8
|
+
Object.defineProperty(exports, "buildSLSAProvenancePredicate", { enumerable: true, get: function () { return provenance_1.buildSLSAProvenancePredicate; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA8C;AAAvB,gGAAA,MAAM,OAAA;AAC7B,2CAIqB;AAFnB,8GAAA,gBAAgB,OAAA;AAChB,0HAAA,4BAA4B,OAAA"}
|
package/lib/intoto.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Predicate, Subject } from './shared.types';
|
|
2
|
+
/**
|
|
3
|
+
* An in-toto statement.
|
|
4
|
+
* https://github.com/in-toto/attestation/blob/main/spec/v1/statement.md
|
|
5
|
+
*/
|
|
6
|
+
export type InTotoStatement = {
|
|
7
|
+
_type: string;
|
|
8
|
+
subject: Subject[];
|
|
9
|
+
predicateType: string;
|
|
10
|
+
predicate: object;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Assembles the given subject and predicate into an in-toto statement.
|
|
14
|
+
* @param subject - The subject of the statement.
|
|
15
|
+
* @param predicate - The predicate of the statement.
|
|
16
|
+
* @returns The constructed in-toto statement.
|
|
17
|
+
*/
|
|
18
|
+
export declare const buildIntotoStatement: (subject: Subject, predicate: Predicate) => InTotoStatement;
|
package/lib/intoto.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildIntotoStatement = void 0;
|
|
4
|
+
const INTOTO_STATEMENT_V1_TYPE = 'https://in-toto.io/Statement/v1';
|
|
5
|
+
/**
|
|
6
|
+
* Assembles the given subject and predicate into an in-toto statement.
|
|
7
|
+
* @param subject - The subject of the statement.
|
|
8
|
+
* @param predicate - The predicate of the statement.
|
|
9
|
+
* @returns The constructed in-toto statement.
|
|
10
|
+
*/
|
|
11
|
+
const buildIntotoStatement = (subject, predicate) => {
|
|
12
|
+
return {
|
|
13
|
+
_type: INTOTO_STATEMENT_V1_TYPE,
|
|
14
|
+
subject: [subject],
|
|
15
|
+
predicateType: predicate.type,
|
|
16
|
+
predicate: predicate.params
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
exports.buildIntotoStatement = buildIntotoStatement;
|
|
20
|
+
//# sourceMappingURL=intoto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intoto.js","sourceRoot":"","sources":["../src/intoto.ts"],"names":[],"mappings":";;;AAEA,MAAM,wBAAwB,GAAG,iCAAiC,CAAA;AAalE;;;;;GAKG;AACI,MAAM,oBAAoB,GAAG,CAClC,OAAgB,EAChB,SAAoB,EACH,EAAE;IACnB,OAAO;QACL,KAAK,EAAE,wBAAwB;QAC/B,OAAO,EAAE,CAAC,OAAO,CAAC;QAClB,aAAa,EAAE,SAAS,CAAC,IAAI;QAC7B,SAAS,EAAE,SAAS,CAAC,MAAM;KAC5B,CAAA;AACH,CAAC,CAAA;AAVY,QAAA,oBAAoB,wBAUhC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
/// <reference types="node" />
|
|
5
|
+
/// <reference types="node" />
|
|
6
|
+
import { AttestOptions } from './attest';
|
|
7
|
+
import type { Attestation, Predicate } from './shared.types';
|
|
8
|
+
export type AttestProvenanceOptions = Omit<AttestOptions, 'predicate' | 'predicateType'>;
|
|
9
|
+
/**
|
|
10
|
+
* Builds an SLSA (Supply Chain Levels for Software Artifacts) provenance
|
|
11
|
+
* predicate using the GitHub Actions Workflow build type.
|
|
12
|
+
* https://slsa.dev/spec/v1.0/provenance
|
|
13
|
+
* https://github.com/slsa-framework/github-actions-buildtypes/tree/main/workflow/v1
|
|
14
|
+
* @param env - The Node.js process environment variables. Defaults to
|
|
15
|
+
* `process.env`.
|
|
16
|
+
* @returns The SLSA provenance predicate.
|
|
17
|
+
*/
|
|
18
|
+
export declare const buildSLSAProvenancePredicate: (env?: NodeJS.ProcessEnv) => Predicate;
|
|
19
|
+
/**
|
|
20
|
+
* Attests the build provenance of the provided subject. Generates the SLSA
|
|
21
|
+
* build provenance predicate, assembles it into an in-toto statement, and
|
|
22
|
+
* attests it.
|
|
23
|
+
*
|
|
24
|
+
* @param options - The options for attesting the provenance.
|
|
25
|
+
* @returns A promise that resolves to the attestation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function attestProvenance(options: AttestProvenanceOptions): Promise<Attestation>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.attestProvenance = exports.buildSLSAProvenancePredicate = void 0;
|
|
13
|
+
const attest_1 = require("./attest");
|
|
14
|
+
const SLSA_PREDICATE_V1_TYPE = 'https://slsa.dev/provenance/v1';
|
|
15
|
+
const GITHUB_BUILDER_ID_PREFIX = 'https://github.com/actions/runner';
|
|
16
|
+
const GITHUB_BUILD_TYPE = 'https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1';
|
|
17
|
+
/**
|
|
18
|
+
* Builds an SLSA (Supply Chain Levels for Software Artifacts) provenance
|
|
19
|
+
* predicate using the GitHub Actions Workflow build type.
|
|
20
|
+
* https://slsa.dev/spec/v1.0/provenance
|
|
21
|
+
* https://github.com/slsa-framework/github-actions-buildtypes/tree/main/workflow/v1
|
|
22
|
+
* @param env - The Node.js process environment variables. Defaults to
|
|
23
|
+
* `process.env`.
|
|
24
|
+
* @returns The SLSA provenance predicate.
|
|
25
|
+
*/
|
|
26
|
+
const buildSLSAProvenancePredicate = (env = process.env) => {
|
|
27
|
+
const workflow = env.GITHUB_WORKFLOW_REF || '';
|
|
28
|
+
// Split just the path and ref from the workflow string.
|
|
29
|
+
// owner/repo/.github/workflows/main.yml@main =>
|
|
30
|
+
// .github/workflows/main.yml, main
|
|
31
|
+
const [workflowPath, workflowRef] = workflow
|
|
32
|
+
.replace(`${env.GITHUB_REPOSITORY}/`, '')
|
|
33
|
+
.split('@');
|
|
34
|
+
return {
|
|
35
|
+
type: SLSA_PREDICATE_V1_TYPE,
|
|
36
|
+
params: {
|
|
37
|
+
buildDefinition: {
|
|
38
|
+
buildType: GITHUB_BUILD_TYPE,
|
|
39
|
+
externalParameters: {
|
|
40
|
+
workflow: {
|
|
41
|
+
ref: workflowRef,
|
|
42
|
+
repository: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}`,
|
|
43
|
+
path: workflowPath
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
internalParameters: {
|
|
47
|
+
github: {
|
|
48
|
+
event_name: env.GITHUB_EVENT_NAME,
|
|
49
|
+
repository_id: env.GITHUB_REPOSITORY_ID,
|
|
50
|
+
repository_owner_id: env.GITHUB_REPOSITORY_OWNER_ID
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
resolvedDependencies: [
|
|
54
|
+
{
|
|
55
|
+
uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`,
|
|
56
|
+
digest: {
|
|
57
|
+
gitCommit: env.GITHUB_SHA
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
runDetails: {
|
|
63
|
+
builder: {
|
|
64
|
+
id: `${GITHUB_BUILDER_ID_PREFIX}/${env.RUNNER_ENVIRONMENT}`
|
|
65
|
+
},
|
|
66
|
+
metadata: {
|
|
67
|
+
invocationId: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}/attempts/${env.GITHUB_RUN_ATTEMPT}`
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
exports.buildSLSAProvenancePredicate = buildSLSAProvenancePredicate;
|
|
74
|
+
/**
|
|
75
|
+
* Attests the build provenance of the provided subject. Generates the SLSA
|
|
76
|
+
* build provenance predicate, assembles it into an in-toto statement, and
|
|
77
|
+
* attests it.
|
|
78
|
+
*
|
|
79
|
+
* @param options - The options for attesting the provenance.
|
|
80
|
+
* @returns A promise that resolves to the attestation.
|
|
81
|
+
*/
|
|
82
|
+
function attestProvenance(options) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const predicate = (0, exports.buildSLSAProvenancePredicate)(process.env);
|
|
85
|
+
return (0, attest_1.attest)(Object.assign(Object.assign({}, options), { predicateType: predicate.type, predicate: predicate.params }));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
exports.attestProvenance = attestProvenance;
|
|
89
|
+
//# sourceMappingURL=provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA8C;AAG9C,MAAM,sBAAsB,GAAG,gCAAgC,CAAA;AAE/D,MAAM,wBAAwB,GAAG,mCAAmC,CAAA;AACpE,MAAM,iBAAiB,GACrB,wEAAwE,CAAA;AAO1E;;;;;;;;GAQG;AACI,MAAM,4BAA4B,GAAG,CAC1C,MAAyB,OAAO,CAAC,GAAG,EACzB,EAAE;IACb,MAAM,QAAQ,GAAG,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAA;IAE9C,wDAAwD;IACxD,gDAAgD;IAChD,qCAAqC;IACrC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,QAAQ;SACzC,OAAO,CAAC,GAAG,GAAG,CAAC,iBAAiB,GAAG,EAAE,EAAE,CAAC;SACxC,KAAK,CAAC,GAAG,CAAC,CAAA;IAEb,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE;YACN,eAAe,EAAE;gBACf,SAAS,EAAE,iBAAiB;gBAC5B,kBAAkB,EAAE;oBAClB,QAAQ,EAAE;wBACR,GAAG,EAAE,WAAW;wBAChB,UAAU,EAAE,GAAG,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,iBAAiB,EAAE;wBAC/D,IAAI,EAAE,YAAY;qBACnB;iBACF;gBACD,kBAAkB,EAAE;oBAClB,MAAM,EAAE;wBACN,UAAU,EAAE,GAAG,CAAC,iBAAiB;wBACjC,aAAa,EAAE,GAAG,CAAC,oBAAoB;wBACvC,mBAAmB,EAAE,GAAG,CAAC,0BAA0B;qBACpD;iBACF;gBACD,oBAAoB,EAAE;oBACpB;wBACE,GAAG,EAAE,OAAO,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,UAAU,EAAE;wBAC9E,MAAM,EAAE;4BACN,SAAS,EAAE,GAAG,CAAC,UAAU;yBAC1B;qBACF;iBACF;aACF;YACD,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,EAAE,EAAE,GAAG,wBAAwB,IAAI,GAAG,CAAC,kBAAkB,EAAE;iBAC5D;gBACD,QAAQ,EAAE;oBACR,YAAY,EAAE,GAAG,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,iBAAiB,iBAAiB,GAAG,CAAC,aAAa,aAAa,GAAG,CAAC,kBAAkB,EAAE;iBACvI;aACF;SACF;KACF,CAAA;AACH,CAAC,CAAA;AAlDY,QAAA,4BAA4B,gCAkDxC;AAED;;;;;;;GAOG;AACH,SAAsB,gBAAgB,CACpC,OAAgC;;QAEhC,MAAM,SAAS,GAAG,IAAA,oCAA4B,EAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC3D,OAAO,IAAA,eAAM,kCACR,OAAO,KACV,aAAa,EAAE,SAAS,CAAC,IAAI,EAC7B,SAAS,EAAE,SAAS,CAAC,MAAM,IAC3B,CAAA;IACJ,CAAC;CAAA;AATD,4CASC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SerializedBundle } from '@sigstore/bundle';
|
|
2
|
+
export type Subject = {
|
|
3
|
+
name: string;
|
|
4
|
+
digest: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
export type Predicate = {
|
|
7
|
+
type: string;
|
|
8
|
+
params: object;
|
|
9
|
+
};
|
|
10
|
+
export type Attestation = {
|
|
11
|
+
bundle: SerializedBundle;
|
|
12
|
+
certificate: string;
|
|
13
|
+
tlogID?: string;
|
|
14
|
+
attestationID?: string;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.types.js","sourceRoot":"","sources":["../src/shared.types.ts"],"names":[],"mappings":""}
|
package/lib/sign.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Bundle } from '@sigstore/bundle';
|
|
3
|
+
/**
|
|
4
|
+
* The payload to be signed (body) and its media type (type).
|
|
5
|
+
*/
|
|
6
|
+
export type Payload = {
|
|
7
|
+
body: Buffer;
|
|
8
|
+
type: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Options for signing a document.
|
|
12
|
+
*/
|
|
13
|
+
export type SignOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* The URL of the Fulcio service.
|
|
16
|
+
*/
|
|
17
|
+
fulcioURL: string;
|
|
18
|
+
/**
|
|
19
|
+
* The URL of the Rekor service.
|
|
20
|
+
*/
|
|
21
|
+
rekorURL?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The URL of the TSA (Time Stamping Authority) server.
|
|
24
|
+
*/
|
|
25
|
+
tsaServerURL?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The timeout duration in milliseconds when communicating with Sigstore
|
|
28
|
+
* services.
|
|
29
|
+
*/
|
|
30
|
+
timeout?: number;
|
|
31
|
+
/**
|
|
32
|
+
* The number of retry attempts.
|
|
33
|
+
*/
|
|
34
|
+
retry?: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Signs the provided payload with a Sigstore-issued certificate and returns the
|
|
38
|
+
* signature bundle.
|
|
39
|
+
* @param payload Payload to be signed.
|
|
40
|
+
* @param options Signing options.
|
|
41
|
+
* @returns A promise that resolves to the Sigstore signature bundle.
|
|
42
|
+
*/
|
|
43
|
+
export declare const signPayload: (payload: Payload, options: SignOptions) => Promise<Bundle>;
|
package/lib/sign.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.signPayload = void 0;
|
|
13
|
+
const sign_1 = require("@sigstore/sign");
|
|
14
|
+
const OIDC_AUDIENCE = 'sigstore';
|
|
15
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
16
|
+
const DEFAULT_RETRIES = 3;
|
|
17
|
+
/**
|
|
18
|
+
* Signs the provided payload with a Sigstore-issued certificate and returns the
|
|
19
|
+
* signature bundle.
|
|
20
|
+
* @param payload Payload to be signed.
|
|
21
|
+
* @param options Signing options.
|
|
22
|
+
* @returns A promise that resolves to the Sigstore signature bundle.
|
|
23
|
+
*/
|
|
24
|
+
const signPayload = (payload, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
const artifact = {
|
|
26
|
+
data: payload.body,
|
|
27
|
+
type: payload.type
|
|
28
|
+
};
|
|
29
|
+
// Sign the artifact and build the bundle
|
|
30
|
+
return initBundleBuilder(options).create(artifact);
|
|
31
|
+
});
|
|
32
|
+
exports.signPayload = signPayload;
|
|
33
|
+
// Assembles the Sigstore bundle builder with the appropriate options
|
|
34
|
+
const initBundleBuilder = (opts) => {
|
|
35
|
+
const identityProvider = new sign_1.CIContextProvider(OIDC_AUDIENCE);
|
|
36
|
+
const timeout = opts.timeout || DEFAULT_TIMEOUT;
|
|
37
|
+
const retry = opts.retry || DEFAULT_RETRIES;
|
|
38
|
+
const witnesses = [];
|
|
39
|
+
const signer = new sign_1.FulcioSigner({
|
|
40
|
+
identityProvider,
|
|
41
|
+
fulcioBaseURL: opts.fulcioURL,
|
|
42
|
+
timeout,
|
|
43
|
+
retry
|
|
44
|
+
});
|
|
45
|
+
if (opts.rekorURL) {
|
|
46
|
+
witnesses.push(new sign_1.RekorWitness({
|
|
47
|
+
rekorBaseURL: opts.rekorURL,
|
|
48
|
+
entryType: 'dsse',
|
|
49
|
+
timeout,
|
|
50
|
+
retry
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
if (opts.tsaServerURL) {
|
|
54
|
+
witnesses.push(new sign_1.TSAWitness({
|
|
55
|
+
tsaBaseURL: opts.tsaServerURL,
|
|
56
|
+
timeout,
|
|
57
|
+
retry
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
return new sign_1.DSSEBundleBuilder({ signer, witnesses });
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=sign.js.map
|
package/lib/sign.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,yCAQuB;AAEvB,MAAM,aAAa,GAAG,UAAU,CAAA;AAChC,MAAM,eAAe,GAAG,KAAK,CAAA;AAC7B,MAAM,eAAe,GAAG,CAAC,CAAA;AAqCzB;;;;;;GAMG;AACI,MAAM,WAAW,GAAG,CACzB,OAAgB,EAChB,OAAoB,EACH,EAAE;IACnB,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAA;IAED,yCAAyC;IACzC,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;AACpD,CAAC,CAAA,CAAA;AAXY,QAAA,WAAW,eAWvB;AAED,qEAAqE;AACrE,MAAM,iBAAiB,GAAG,CAAC,IAAiB,EAAiB,EAAE;IAC7D,MAAM,gBAAgB,GAAG,IAAI,wBAAiB,CAAC,aAAa,CAAC,CAAA;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,eAAe,CAAA;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,eAAe,CAAA;IAC3C,MAAM,SAAS,GAAc,EAAE,CAAA;IAE/B,MAAM,MAAM,GAAG,IAAI,mBAAY,CAAC;QAC9B,gBAAgB;QAChB,aAAa,EAAE,IAAI,CAAC,SAAS;QAC7B,OAAO;QACP,KAAK;KACN,CAAC,CAAA;IAEF,IAAI,IAAI,CAAC,QAAQ,EAAE;QACjB,SAAS,CAAC,IAAI,CACZ,IAAI,mBAAY,CAAC;YACf,YAAY,EAAE,IAAI,CAAC,QAAQ;YAC3B,SAAS,EAAE,MAAM;YACjB,OAAO;YACP,KAAK;SACN,CAAC,CACH,CAAA;KACF;IAED,IAAI,IAAI,CAAC,YAAY,EAAE;QACrB,SAAS,CAAC,IAAI,CACZ,IAAI,iBAAU,CAAC;YACb,UAAU,EAAE,IAAI,CAAC,YAAY;YAC7B,OAAO;YACP,KAAK;SACN,CAAC,CACH,CAAA;KACF;IAED,OAAO,IAAI,wBAAiB,CAAC,EAAC,MAAM,EAAE,SAAS,EAAC,CAAC,CAAA;AACnD,CAAC,CAAA"}
|
package/lib/store.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes an attestation to the repository's attestations endpoint.
|
|
3
|
+
* @param attestation - The attestation to write.
|
|
4
|
+
* @param token - The GitHub token for authentication.
|
|
5
|
+
* @returns The ID of the attestation.
|
|
6
|
+
* @throws Error if the attestation fails to persist.
|
|
7
|
+
*/
|
|
8
|
+
export declare const writeAttestation: (attestation: unknown, token: string) => Promise<string>;
|
package/lib/store.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.writeAttestation = void 0;
|
|
39
|
+
const github = __importStar(require("@actions/github"));
|
|
40
|
+
const make_fetch_happen_1 = __importDefault(require("make-fetch-happen"));
|
|
41
|
+
const CREATE_ATTESTATION_REQUEST = 'POST /repos/{owner}/{repo}/attestations';
|
|
42
|
+
/**
|
|
43
|
+
* Writes an attestation to the repository's attestations endpoint.
|
|
44
|
+
* @param attestation - The attestation to write.
|
|
45
|
+
* @param token - The GitHub token for authentication.
|
|
46
|
+
* @returns The ID of the attestation.
|
|
47
|
+
* @throws Error if the attestation fails to persist.
|
|
48
|
+
*/
|
|
49
|
+
const writeAttestation = (attestation, token) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
var _a;
|
|
51
|
+
const octokit = github.getOctokit(token, { request: { fetch: make_fetch_happen_1.default } });
|
|
52
|
+
try {
|
|
53
|
+
const response = yield octokit.request(CREATE_ATTESTATION_REQUEST, {
|
|
54
|
+
owner: github.context.repo.owner,
|
|
55
|
+
repo: github.context.repo.repo,
|
|
56
|
+
data: { bundle: attestation }
|
|
57
|
+
});
|
|
58
|
+
return (_a = response.data) === null || _a === void 0 ? void 0 : _a.id;
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
const message = err instanceof Error ? err.message : err;
|
|
62
|
+
throw new Error(`Failed to persist attestation: ${message}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
exports.writeAttestation = writeAttestation;
|
|
66
|
+
//# sourceMappingURL=store.js.map
|
package/lib/store.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wDAAyC;AACzC,0EAAqC;AAErC,MAAM,0BAA0B,GAAG,yCAAyC,CAAA;AAE5E;;;;;;GAMG;AACI,MAAM,gBAAgB,GAAG,CAC9B,WAAoB,EACpB,KAAa,EACI,EAAE;;IACnB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,EAAC,OAAO,EAAE,EAAC,KAAK,EAAL,2BAAK,EAAC,EAAC,CAAC,CAAA;IAE5D,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,0BAA0B,EAAE;YACjE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;YAChC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;YAC9B,IAAI,EAAE,EAAC,MAAM,EAAE,WAAW,EAAC;SAC5B,CAAC,CAAA;QAEF,OAAO,MAAA,QAAQ,CAAC,IAAI,0CAAE,EAAE,CAAA;KACzB;IAAC,OAAO,GAAG,EAAE;QACZ,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA;QACxD,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAA;KAC7D;AACH,CAAC,CAAA,CAAA;AAlBY,QAAA,gBAAgB,oBAkB5B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@actions/attest",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Actions attestation lib",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"github",
|
|
7
|
+
"actions",
|
|
8
|
+
"attestation"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/actions/toolkit/tree/main/packages/attest",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"main": "lib/index.js",
|
|
13
|
+
"types": "lib/index.d.ts",
|
|
14
|
+
"directories": {
|
|
15
|
+
"lib": "lib",
|
|
16
|
+
"test": "__tests__"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"provenance": true
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/actions/toolkit.git",
|
|
28
|
+
"directory": "packages/attest"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test": "echo \"Error: run tests from root\" && exit 1",
|
|
32
|
+
"tsc": "tsc"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/actions/toolkit/issues"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@sigstore/mock": "^0.6.5",
|
|
39
|
+
"@sigstore/rekor-types": "^2.0.0",
|
|
40
|
+
"@types/make-fetch-happen": "^10.0.4",
|
|
41
|
+
"nock": "^13.5.1"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@actions/github": "^6.0.0",
|
|
45
|
+
"@sigstore/bundle": "^2.2.0",
|
|
46
|
+
"@sigstore/sign": "^2.2.3",
|
|
47
|
+
"make-fetch-happen": "^13.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|