@effected/github-actions 0.23.1 → 0.25.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/Action.js +1 -2
- package/ActionCache.js +1 -2
- package/ActionEnvironment.js +7 -10
- package/ActionInput.js +15 -19
- package/ActionLogger.js +1 -2
- package/ActionOutputs.js +1 -2
- package/ActionState.js +1 -2
- package/ActionsIdentityToken.js +6 -7
- package/ActionsProvenance.js +18 -17
- package/Artifact.js +4 -4
- package/BlobEnvelope.js +1 -2
- package/BlobStore.githubCache.js +1 -2
- package/BlobStore.js +59 -30
- package/BlobTransfer.js +1 -2
- package/CacheKey.js +1 -2
- package/CheckDocument.js +1 -2
- package/CheckState.js +1 -2
- package/ChildEnv.js +1 -2
- package/DetachedProcess.js +1 -2
- package/DryRun.js +1 -2
- package/GitHubMarkdown.js +1 -2
- package/GitHubToken.js +1 -2
- package/ManagedDocument.js +1 -2
- package/OidcTokenIssuer.js +24 -54
- package/PackageManagerInstaller.js +20 -24
- package/README.md +3 -3
- package/Secret.js +11 -8
- package/ToolInstaller.js +4 -4
- package/index.d.ts +51 -125
- package/index.js +2 -2
- package/internal/actionsResults.js +6 -6
- package/internal/archiveCommands.js +1 -2
- package/internal/cacheService.js +1 -2
- package/internal/digest.js +1 -2
- package/internal/fsProbe.js +1 -2
- package/internal/json.js +11 -0
- package/internal/pnpmExe.js +1 -2
- package/internal/runner.js +22 -3
- package/internal/runnerFile.js +1 -2
- package/internal/shim.js +1 -2
- package/internal/spawn.js +1 -2
- package/internal/twirp.js +1 -2
- package/internal/unstubbed.js +1 -2
- package/package.json +13 -10
- package/internal/jwt.js +0 -42
- package/internal/sigv4.js +0 -115
package/internal/spawn.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Stream } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/internal/spawn.ts
|
|
4
4
|
/**
|
|
5
5
|
* Spawn `command` once, drain `stdout`+`stderr`, then read the exit code from
|
|
6
6
|
* the same handle. Never fails on a non-zero exit — that is the caller's
|
|
@@ -14,5 +14,4 @@ const spawnOnce = (spawner, command) => Effect.scoped(Effect.gen(function* () {
|
|
|
14
14
|
};
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
|
-
//#endregion
|
|
18
17
|
export { spawnOnce };
|
package/internal/twirp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect, Schedule } from "effect";
|
|
2
2
|
import { HttpClientRequest } from "effect/http";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/twirp.ts
|
|
5
5
|
/**
|
|
6
6
|
* Returned instead of a failure when the backend answers HTTP 409.
|
|
7
7
|
*
|
|
@@ -110,5 +110,4 @@ const stringField = (body, name) => {
|
|
|
110
110
|
/** Whether a Twirp response carries `ok: true`. @internal */
|
|
111
111
|
const isOk = (body) => field(body, "ok") === true;
|
|
112
112
|
|
|
113
|
-
//#endregion
|
|
114
113
|
export { CONFLICT, field, isOk, isRetryable, stringField, twirpCall, twirpFailureFields };
|
package/internal/unstubbed.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/internal/unstubbed.ts
|
|
4
4
|
/**
|
|
5
5
|
* The die-on-call members of `<double>.makeTest`: `dies("save")` is an
|
|
6
6
|
* `Effect` that defects naming `save` when run. Each package double binds its
|
|
@@ -12,5 +12,4 @@ const unstubbed = (double) => (member) => Effect.sync(() => {
|
|
|
12
12
|
throw new Error(`${double}: ${member}() was called but not stubbed — pass a \`${member}\` override.`);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
//#endregion
|
|
16
15
|
export { unstubbed };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/github-actions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The GitHub Actions runtime: env, inputs, outputs, state, logging, cache, artifacts, blob storage, OIDC and the token bridge.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,15 +39,18 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@azure/storage-blob": "^12.33.0",
|
|
42
|
-
"@effected/
|
|
43
|
-
"@effected/github
|
|
44
|
-
"@effected/
|
|
45
|
-
"@effected/
|
|
46
|
-
"@effected/
|
|
47
|
-
"@effected/
|
|
48
|
-
"@effected/
|
|
49
|
-
"@effected/
|
|
50
|
-
"@effected/
|
|
42
|
+
"@effected/crypto": "^0.1.0",
|
|
43
|
+
"@effected/github": "^0.23.0",
|
|
44
|
+
"@effected/github-commands": "^0.6.0",
|
|
45
|
+
"@effected/glob": "^0.14.0",
|
|
46
|
+
"@effected/jwt": "^0.5.0",
|
|
47
|
+
"@effected/markdown": "^0.20.0",
|
|
48
|
+
"@effected/npm": "^0.25.0",
|
|
49
|
+
"@effected/oidc": "^0.1.0",
|
|
50
|
+
"@effected/sbom": "^0.15.0",
|
|
51
|
+
"@effected/semver": "^0.15.0",
|
|
52
|
+
"@effected/templates": "^0.14.0",
|
|
53
|
+
"@effected/walker": "^0.19.0"
|
|
51
54
|
},
|
|
52
55
|
"peerDependencies": {
|
|
53
56
|
"@effect/platform-node": "^4.0.0",
|
package/internal/jwt.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Result } from "effect";
|
|
2
|
-
import * as Base64Url from "effect/encoding/Base64Url";
|
|
3
|
-
|
|
4
|
-
//#region src/internal/jwt.ts
|
|
5
|
-
/**
|
|
6
|
-
* The decoded payload of `token` — the middle segment, base64url JSON —
|
|
7
|
-
* without any check on the signature.
|
|
8
|
-
*
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
const payloadOf = (token) => {
|
|
12
|
-
const segments = token.split(".");
|
|
13
|
-
const payload = segments[1];
|
|
14
|
-
if (segments.length !== 3 || payload === void 0 || payload === "") return Result.fail({ detail: `expected three segments, got ${segments.length}` });
|
|
15
|
-
const json = Base64Url.decodeString(payload);
|
|
16
|
-
if (Result.isFailure(json)) return Result.fail({
|
|
17
|
-
detail: "the payload is not base64url JSON",
|
|
18
|
-
cause: json.failure
|
|
19
|
-
});
|
|
20
|
-
try {
|
|
21
|
-
return Result.succeed(JSON.parse(json.success));
|
|
22
|
-
} catch (cause) {
|
|
23
|
-
return Result.fail({
|
|
24
|
-
detail: "the payload is not base64url JSON",
|
|
25
|
-
cause
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* An **unsigned** JWT: `header.payload.unsigned`, each JSON segment
|
|
31
|
-
* base64url-encoded. For building test doubles and nothing else — the
|
|
32
|
-
* signature segment is a placeholder, so this token fails any verifier.
|
|
33
|
-
*
|
|
34
|
-
* @internal
|
|
35
|
-
*/
|
|
36
|
-
const unsignedJwt = (header, payload) => {
|
|
37
|
-
const segment = (value) => Base64Url.encode(JSON.stringify(value));
|
|
38
|
-
return `${segment(header)}.${segment(payload)}.unsigned`;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
//#endregion
|
|
42
|
-
export { payloadOf, unsignedJwt };
|
package/internal/sigv4.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { sha256Hex } from "./digest.js";
|
|
2
|
-
import { createHmac } from "node:crypto";
|
|
3
|
-
|
|
4
|
-
//#region src/internal/sigv4.ts
|
|
5
|
-
/**
|
|
6
|
-
* AWS Signature Version 4, for S3-compatible object stores.
|
|
7
|
-
*
|
|
8
|
-
* @remarks
|
|
9
|
-
* **Pure**, and about a hundred lines, which is the whole argument for not
|
|
10
|
-
* taking an `@aws-sdk/*` dependency to obtain it. Signing is a specified
|
|
11
|
-
* algorithm over strings and HMACs; the SDK around it exists to manage
|
|
12
|
-
* credentials, retries and a service catalogue this package does not want.
|
|
13
|
-
*
|
|
14
|
-
* `node:crypto` rather than core `Crypto` because core's `Crypto` offers only
|
|
15
|
-
* one-shot SHA digests over bytes already in memory — no HMAC, no incremental
|
|
16
|
-
* hasher (see `internal/digest.ts`, this package's other `node:crypto`
|
|
17
|
-
* licence). This package is the one place in the kit where a `node:` import
|
|
18
|
-
* is sanctioned, and this is one of the four reasons.
|
|
19
|
-
*
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
const ALGORITHM = "AWS4-HMAC-SHA256";
|
|
23
|
-
const hmac = (key, value) => new Uint8Array(createHmac("sha256", key).update(value).digest());
|
|
24
|
-
/**
|
|
25
|
-
* Percent-encode one path segment the way SigV4 requires.
|
|
26
|
-
*
|
|
27
|
-
* @remarks
|
|
28
|
-
* `encodeURIComponent` leaves `!'()*` alone and AWS does not, so a key
|
|
29
|
-
* containing any of them signs one string and requests another — which fails as
|
|
30
|
-
* an opaque `SignatureDoesNotMatch` rather than as anything that names the
|
|
31
|
-
* character. The unreserved set is exactly `A-Za-z0-9-_.~`.
|
|
32
|
-
*/
|
|
33
|
-
const uriEncode = (value) => encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
34
|
-
/** `20130524T000000Z` and `20130524`, the two forms the algorithm uses. */
|
|
35
|
-
const timestamps = (now) => {
|
|
36
|
-
const amzDate = `${now.toISOString().replace(/[:-]|\.\d{3}/g, "").slice(0, 15)}Z`;
|
|
37
|
-
return {
|
|
38
|
-
amzDate,
|
|
39
|
-
dateStamp: amzDate.slice(0, 8)
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Assemble the headers that will be signed, and the canonical request over them.
|
|
44
|
-
*
|
|
45
|
-
* @remarks
|
|
46
|
-
* Exported separately from {@link sign} so a test can pin it against AWS's
|
|
47
|
-
* **own documented** canonical request rather than against this
|
|
48
|
-
* implementation's output.
|
|
49
|
-
*/
|
|
50
|
-
const canonicalize = (request, credentials) => {
|
|
51
|
-
const { amzDate, dateStamp } = timestamps(request.now);
|
|
52
|
-
const payloadHash = sha256Hex(request.body);
|
|
53
|
-
const headers = {
|
|
54
|
-
...request.headers,
|
|
55
|
-
host: request.host,
|
|
56
|
-
"x-amz-date": amzDate,
|
|
57
|
-
"x-amz-content-sha256": payloadHash,
|
|
58
|
-
...credentials.sessionToken === void 0 ? {} : { "x-amz-security-token": credentials.sessionToken }
|
|
59
|
-
};
|
|
60
|
-
const lowered = new Map(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), value]));
|
|
61
|
-
const canonicalNames = [...lowered.keys()].sort();
|
|
62
|
-
const canonicalHeaders = canonicalNames.map((name) => `${name}:${(lowered.get(name) ?? "").trim().replace(/\s+/g, " ")}\n`).join("");
|
|
63
|
-
const signedHeaders = canonicalNames.join(";");
|
|
64
|
-
const canonicalPath = `/${request.path.split("/").filter((segment) => segment !== "").map(uriEncode).join("/")}`;
|
|
65
|
-
return {
|
|
66
|
-
headers,
|
|
67
|
-
signedHeaders,
|
|
68
|
-
amzDate,
|
|
69
|
-
dateStamp,
|
|
70
|
-
canonicalRequest: [
|
|
71
|
-
request.method,
|
|
72
|
-
canonicalPath,
|
|
73
|
-
"",
|
|
74
|
-
canonicalHeaders,
|
|
75
|
-
signedHeaders,
|
|
76
|
-
payloadHash
|
|
77
|
-
].join("\n")
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Derive a signing key.
|
|
82
|
-
*
|
|
83
|
-
* @remarks
|
|
84
|
-
* Four nested HMACs over date, region, service and the literal `aws4_request`.
|
|
85
|
-
* Exported so a test can reproduce AWS's documented derivation example.
|
|
86
|
-
*/
|
|
87
|
-
const signingKey = (secretAccessKey, dateStamp, region, service) => hmac(hmac(hmac(hmac(`AWS4${secretAccessKey}`, dateStamp), region), service), "aws4_request");
|
|
88
|
-
/**
|
|
89
|
-
* Sign a request, returning the headers to send.
|
|
90
|
-
*
|
|
91
|
-
* @remarks
|
|
92
|
-
* The returned record is the caller's headers **plus** everything signing added
|
|
93
|
-
* — `host`, `x-amz-date`, `x-amz-content-sha256`, the optional
|
|
94
|
-
* `x-amz-security-token` and `authorization` — so a caller sends exactly what
|
|
95
|
-
* was signed rather than assembling a second, subtly different set.
|
|
96
|
-
*/
|
|
97
|
-
const sign = (request, credentials) => {
|
|
98
|
-
const { headers, canonicalRequest, signedHeaders, amzDate, dateStamp } = canonicalize(request, credentials);
|
|
99
|
-
const scope = `${dateStamp}/${credentials.region}/${credentials.service}/aws4_request`;
|
|
100
|
-
const stringToSign = [
|
|
101
|
-
ALGORITHM,
|
|
102
|
-
amzDate,
|
|
103
|
-
scope,
|
|
104
|
-
sha256Hex(canonicalRequest)
|
|
105
|
-
].join("\n");
|
|
106
|
-
const key = signingKey(credentials.secretAccessKey, dateStamp, credentials.region, credentials.service);
|
|
107
|
-
const signature = Buffer.from(hmac(key, stringToSign)).toString("hex");
|
|
108
|
-
return {
|
|
109
|
-
...headers,
|
|
110
|
-
authorization: `${ALGORITHM} Credential=${credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
//#endregion
|
|
115
|
-
export { canonicalize, sha256Hex as digestHex, sign, signingKey, uriEncode };
|