@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/internal/spawn.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Effect, Stream } from "effect";
2
2
 
3
- //#region src/internal/spawn.ts
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
- //#region src/internal/twirp.ts
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 };
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
2
 
3
- //#region src/internal/unstubbed.ts
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.23.1",
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/github": "^0.21.0",
43
- "@effected/github-commands": "^0.5.0",
44
- "@effected/glob": "^0.13.0",
45
- "@effected/markdown": "^0.19.0",
46
- "@effected/npm": "^0.23.0",
47
- "@effected/sbom": "^0.13.0",
48
- "@effected/semver": "^0.14.0",
49
- "@effected/templates": "^0.13.0",
50
- "@effected/walker": "^0.18.0"
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 };