@cat-factory/eks 0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @cat-factory/eks
2
+
3
+ Opt-in AWS **EKS** backends for cat-factory — a runner backend (per-run agent pods) and an
4
+ ephemeral-environment backend (per-PR namespaces), both on an Amazon EKS cluster.
5
+
6
+ ## Why this is a thin package
7
+
8
+ An EKS cluster's API server **is** a standard Kubernetes API server, so this package **reuses
9
+ the entire native Kubernetes transport/provider** from `@cat-factory/integrations`
10
+ (`KubernetesRunnerTransport`, `KubernetesEnvironmentProvider`, `KubernetesApiClient`) verbatim.
11
+ The only EKS-specific piece is **authentication**: EKS doesn't use a static ServiceAccount
12
+ bearer token — it expects a short-lived IAM token (a SigV4-presigned STS `GetCallerIdentity`
13
+ URL, prefixed `k8s-aws-v1.`, the exact token `aws eks get-token` produces). That token is
14
+ minted here with WebCrypto (`eks-auth.logic.ts`), so the package carries **no runtime AWS SDK
15
+ dependency** and is runtime-neutral. It's injected through the async token seam
16
+ `KubernetesApiClient` exposes, so no transport logic is duplicated.
17
+
18
+ ## Enabling it
19
+
20
+ The backends are **not** in the default registries (which stay AWS-free). A facade opts in by
21
+ registering them **by reference** from its composition root (the Node/local facades already do
22
+ this in `backend/runtimes/node/src/container.ts`):
23
+
24
+ ```ts
25
+ import { eksRunnerBackend, eksEnvironmentBackend } from '@cat-factory/eks'
26
+ registries.runnerBackendRegistry.register(eksRunnerBackend)
27
+ registries.environmentBackendRegistry.register(eksEnvironmentBackend)
28
+ ```
29
+
30
+ A workspace then connects an `eks` runner/environment backend with an `EksRunnerConfig` /
31
+ `EksProvisionConfig` (the Kubernetes config — apiserver endpoint, CA, namespace, image — plus
32
+ `region` + `clusterName`), and the AWS credentials (`awsAccessKeyId` / `awsSecretAccessKey` /
33
+ optional `awsSessionToken`) in the write-only secret bundle.
34
+
35
+ Both facades register the backends by reference (`backend/runtimes/node/src/container.ts` and
36
+ `backend/runtimes/cloudflare/src/infrastructure/container.ts`), keeping the runtimes symmetric
37
+ with the native `kubernetes` backend they extend.
38
+
39
+ > **Runtime reach.** A real EKS cluster's apiserver presents a **private CA**, which only a
40
+ > runtime that can pin a custom CA (Node/local, via `undici`) can verify — the SAME constraint a
41
+ > private-CA `kubernetes` connection already carries. The Worker registers the `eks` kind for
42
+ > symmetry, but a connection to such a cluster is rejected up front at registration when the
43
+ > runtime can't honor the custom CA (`customTlsSupported: false`), so it fails loudly rather than
44
+ > silently at first dispatch.
45
+
46
+ ### UI reach
47
+
48
+ The **runner** backend is a first-class UI citizen: it self-describes its connect form via the
49
+ `RunnerBackendProvider.form` descriptor, so the SPA renders it generically (region / cluster /
50
+ credentials + the shared apiserver fields) with **no** EKS-specific frontend code — the same
51
+ descriptor-driven path the built-in Kubernetes runner backend now uses.
52
+
53
+ The **environment** backend is functional when resolved by kind, but is not yet surfaced as its
54
+ own first-class environment _engine_ in the SPA infra-handler selector (the connect flow would
55
+ lower to `{ kind: 'eks' }` rather than `{ kind: 'kubernetes' }`). That needs a dedicated
56
+ `InfraEngine('eks')` threaded through the contract engine union + `handlerConfigToBackendConfig`
57
+
58
+ - the per-provision-type SPA forms — tracked in
59
+ [`docs/initiatives/descriptor-driven-infra-forms.md`](../../../docs/initiatives/descriptor-driven-infra-forms.md).
60
+
61
+ ## Tests
62
+
63
+ - **Unit** (`pnpm --filter @cat-factory/eks test:run`, runs in the required CI gate): the
64
+ SigV4/STS token minter golden vector + the `{ kind: 'eks' }` contract round-trip. No cluster.
65
+ - **Integration** (`pnpm --filter @cat-factory/eks test:integration`): drives the EKS
66
+ transport/provider against a **real** apiserver. Self-skips unless `EKS_IT_*` is set. Runs in
67
+ the **non-blocking** `test-eks` CI job (see `.github/workflows/ci.yml`).
68
+
69
+ ### Running the integration suite against floci
70
+
71
+ [floci](https://floci.io) is a local, LocalStack-compatible AWS emulator whose EKS "real mode"
72
+ stands up a **real k3s container per EKS cluster** and exposes its Kubernetes API server on a host
73
+ port. Boot floci (pinned to the version this suite is validated against), create a cluster with the
74
+ AWS CLI, then export the connection:
75
+
76
+ ```sh
77
+ docker run -d --name floci -p 4566:4566 -v /var/run/docker.sock:/var/run/docker.sock -u root floci/floci:1.5.30
78
+ export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1
79
+ aws --endpoint-url=http://localhost:4566 eks create-cluster --name cat-factory-it \
80
+ --role-arn arn:aws:iam::000000000000:role/eks --resources-vpc-config '{}'
81
+ # ...wait for ACTIVE, then read endpoint + CA:
82
+ export EKS_IT_APISERVER=$(aws --endpoint-url=http://localhost:4566 eks describe-cluster --name cat-factory-it --query cluster.endpoint --output text)
83
+ export EKS_IT_REGION=us-east-1 EKS_IT_CLUSTER_NAME=cat-factory-it
84
+ export EKS_IT_ACCESS_KEY_ID=test EKS_IT_SECRET_ACCESS_KEY=test
85
+ export EKS_IT_STS_HOST=localhost:4566 EKS_IT_INSECURE=1
86
+ export EKS_IT_RUNNER_IMAGE=cat-factory-mock-harness:it # runner suite only
87
+ pnpm --filter @cat-factory/eks run test:integration
88
+ ```
89
+
90
+ The `stsHost` override (`EKS_IT_STS_HOST` → the config's `stsHost`) points the presigned STS
91
+ `GetCallerIdentity` URL at floci instead of real AWS. See `src/test-support/eks-cluster.ts` for the
92
+ full env list and for exactly what floci does — and does not — cover at the auth layer.
@@ -0,0 +1,7 @@
1
+ import { KubernetesApiClient, KubernetesEnvironmentProvider } from '@cat-factory/integrations';
2
+ import type { KubernetesEnvironmentConfig, ProviderConfigField, SecretResolver } from '@cat-factory/kernel';
3
+ export declare class EksEnvironmentProvider extends KubernetesEnvironmentProvider {
4
+ protected makeClient(config: KubernetesEnvironmentConfig, resolveSecret: SecretResolver): KubernetesApiClient;
5
+ describeConfig(): ProviderConfigField[];
6
+ }
7
+ //# sourceMappingURL=EksEnvironmentProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EksEnvironmentProvider.d.ts","sourceRoot":"","sources":["../src/EksEnvironmentProvider.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAE9B,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAA;AAU5B,qBAAa,sBAAuB,SAAQ,6BAA6B;IACvE,UAAmB,UAAU,CAC3B,MAAM,EAAE,2BAA2B,EACnC,aAAa,EAAE,cAAc,GAC5B,mBAAmB,CAQrB;IAEQ,cAAc,IAAI,mBAAmB,EAAE,CAiB/C;CACF"}
@@ -0,0 +1,35 @@
1
+ import { EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY, } from '@cat-factory/contracts';
2
+ import { KubernetesApiClient, KubernetesEnvironmentProvider, kubernetesLogic, } from '@cat-factory/integrations';
3
+ import { eksTokenProvider } from './eks-auth.logic.js';
4
+ // The AWS EKS ephemeral-environment provider. An EKS apiserver is a standard Kubernetes
5
+ // apiserver, so per-PR namespace creation, server-side manifest apply, deployment-readiness
6
+ // polling and LoadBalancer/Ingress/Gateway URL resolution are IDENTICAL — this reuses all of
7
+ // `KubernetesEnvironmentProvider` and only overrides the auth seam (`makeClient`) to inject the
8
+ // minted EKS IAM token, plus `describeConfig` to surface the AWS credential fields instead of a
9
+ // static ServiceAccount token. The parsed config rides the stored manifest's `providerConfig`
10
+ // (an `EksProvisionConfig`), so `region`/`clusterName` are present at runtime.
11
+ export class EksEnvironmentProvider extends KubernetesEnvironmentProvider {
12
+ makeClient(config, resolveSecret) {
13
+ const eks = config;
14
+ return new KubernetesApiClient(config, resolveSecret, kubernetesLogic.KUBERNETES_TOKEN_KEY, eksTokenProvider(eks, resolveSecret));
15
+ }
16
+ describeConfig() {
17
+ // EKS authenticates with AWS credentials (used to mint the short-lived apiserver IAM token),
18
+ // not a static ServiceAccount token — so the unconfigured banner clears on these keys.
19
+ return [
20
+ {
21
+ key: EKS_ACCESS_KEY_ID_SECRET_KEY,
22
+ label: 'AWS access key id',
23
+ secret: true,
24
+ required: true,
25
+ },
26
+ {
27
+ key: EKS_SECRET_ACCESS_KEY_SECRET_KEY,
28
+ label: 'AWS secret access key',
29
+ secret: true,
30
+ required: true,
31
+ },
32
+ ];
33
+ }
34
+ }
35
+ //# sourceMappingURL=EksEnvironmentProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EksEnvironmentProvider.js","sourceRoot":"","sources":["../src/EksEnvironmentProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,GAEjC,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,eAAe,GAChB,MAAM,2BAA2B,CAAA;AAMlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEtD,wFAAwF;AACxF,4FAA4F;AAC5F,6FAA6F;AAC7F,gGAAgG;AAChG,gGAAgG;AAChG,8FAA8F;AAC9F,+EAA+E;AAC/E,MAAM,OAAO,sBAAuB,SAAQ,6BAA6B;IACpD,UAAU,CAC3B,MAAmC,EACnC,aAA6B;QAE7B,MAAM,GAAG,GAAG,MAA4B,CAAA;QACxC,OAAO,IAAI,mBAAmB,CAC5B,MAAM,EACN,aAAa,EACb,eAAe,CAAC,oBAAoB,EACpC,gBAAgB,CAAC,GAAG,EAAE,aAAa,CAAC,CACrC,CAAA;IACH,CAAC;IAEQ,cAAc;QACrB,6FAA6F;QAC7F,uFAAuF;QACvF,OAAO;YACL;gBACE,GAAG,EAAE,4BAA4B;gBACjC,KAAK,EAAE,mBAAmB;gBAC1B,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,IAAI;aACf;YACD;gBACE,GAAG,EAAE,gCAAgC;gBACrC,KAAK,EAAE,uBAAuB;gBAC9B,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,IAAI;aACf;SACF,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import type { EksRunnerConfig } from '@cat-factory/contracts';
2
+ import { KubernetesRunnerTransport } from '@cat-factory/integrations';
3
+ import type { SecretResolver } from '@cat-factory/kernel';
4
+ export declare class EksRunnerTransport extends KubernetesRunnerTransport {
5
+ constructor(config: EksRunnerConfig, resolveSecret: SecretResolver);
6
+ }
7
+ //# sourceMappingURL=EksRunnerTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EksRunnerTransport.d.ts","sourceRoot":"","sources":["../src/EksRunnerTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAUzD,qBAAa,kBAAmB,SAAQ,yBAAyB;IAC/D,YAAY,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAEjE;CACF"}
@@ -0,0 +1,15 @@
1
+ import { KubernetesRunnerTransport } from '@cat-factory/integrations';
2
+ import { eksTokenProvider } from './eks-auth.logic.js';
3
+ // The AWS EKS runner transport. An EKS cluster's apiserver IS a standard Kubernetes apiserver,
4
+ // so this reuses the ENTIRE native Kubernetes per-run-pod transport (pod creation, readiness
5
+ // wait, pod-proxy dispatch/poll, eviction handling) VERBATIM — the only difference is auth. It
6
+ // injects the async EKS token provider (a SigV4-presigned STS token minted per use from the
7
+ // workspace's AWS credentials + `region`/`clusterName`) through the transport's token seam, so
8
+ // there is zero duplicated transport logic. An `EksRunnerConfig` is a `KubernetesRunnerConfig`
9
+ // plus the AWS `region`/`clusterName`, so it is passed straight to the base class.
10
+ export class EksRunnerTransport extends KubernetesRunnerTransport {
11
+ constructor(config, resolveSecret) {
12
+ super(config, resolveSecret, eksTokenProvider(config, resolveSecret));
13
+ }
14
+ }
15
+ //# sourceMappingURL=EksRunnerTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EksRunnerTransport.js","sourceRoot":"","sources":["../src/EksRunnerTransport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEtD,+FAA+F;AAC/F,6FAA6F;AAC7F,+FAA+F;AAC/F,4FAA4F;AAC5F,+FAA+F;AAC/F,+FAA+F;AAC/F,mFAAmF;AACnF,MAAM,OAAO,kBAAmB,SAAQ,yBAAyB;IAC/D,YAAY,MAAuB,EAAE,aAA6B;QAChE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,gBAAgB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAA;IACvE,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import type { KubernetesTokenProvider } from '@cat-factory/integrations';
2
+ import type { SecretResolver } from '@cat-factory/kernel';
3
+ /** Static AWS credentials the SigV4 signature is computed from. */
4
+ export interface EksAwsCredentials {
5
+ accessKeyId: string;
6
+ secretAccessKey: string;
7
+ /** Present for temporary (STS / assume-role) credentials; folded in as `X-Amz-Security-Token`. */
8
+ sessionToken?: string;
9
+ }
10
+ export interface MintEksTokenParams {
11
+ region: string;
12
+ clusterName: string;
13
+ credentials: EksAwsCredentials;
14
+ /** Epoch ms for `X-Amz-Date`. Injectable so the token is deterministic in tests. Defaults to `Date.now()`. */
15
+ now?: number;
16
+ /**
17
+ * STS host override, e.g. floci's emulated STS endpoint. Defaults to the regional public STS
18
+ * host `sts.<region>.amazonaws.com`. Only the HOST is overridable (the scheme stays https).
19
+ */
20
+ stsHost?: string;
21
+ }
22
+ /**
23
+ * Mint an EKS apiserver bearer token (`k8s-aws-v1.<base64url(presigned STS URL)>`).
24
+ * Pure + deterministic given `now`.
25
+ */
26
+ export declare function mintEksToken(params: MintEksTokenParams): Promise<string>;
27
+ /**
28
+ * Build the async token provider `KubernetesApiClient` calls per request. It reads the AWS
29
+ * credentials from the run's secret bundle and mints a token, caching it briefly so a single
30
+ * transport call (e.g. an apply loop) mints once rather than per apiserver request.
31
+ */
32
+ export declare function eksTokenProvider(cluster: {
33
+ region: string;
34
+ clusterName: string;
35
+ stsHost?: string;
36
+ }, resolveSecret: SecretResolver): KubernetesTokenProvider;
37
+ /** Read the AWS credentials from the encrypted secret bundle. Throws if the required keys are absent. */
38
+ export declare function readAwsCredentials(resolveSecret: SecretResolver): EksAwsCredentials;
39
+ //# sourceMappingURL=eks-auth.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-auth.logic.d.ts","sourceRoot":"","sources":["../src/eks-auth.logic.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AA2BzD,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,kGAAkG;IAClG,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,iBAAiB,CAAA;IAC9B,8GAA8G;IAC9G,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C9E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAClE,aAAa,EAAE,cAAc,GAC5B,uBAAuB,CAazB;AAED,yGAAyG;AACzG,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,cAAc,GAAG,iBAAiB,CAWnF"}
@@ -0,0 +1,174 @@
1
+ import { EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY, EKS_SESSION_TOKEN_SECRET_KEY, } from '@cat-factory/contracts';
2
+ // ---------------------------------------------------------------------------
3
+ // AWS EKS apiserver authentication.
4
+ //
5
+ // EKS does not use a static ServiceAccount bearer token. Instead the apiserver is fronted by
6
+ // the aws-iam-authenticator webhook, which accepts a token that is a base64url-encoded,
7
+ // SigV4-PRESIGNED `sts:GetCallerIdentity` URL, prefixed with `k8s-aws-v1.` — the exact token
8
+ // `aws eks get-token` / the AWS SDKs produce. The EKS cluster name is bound into the signature
9
+ // via the SIGNED header `x-k8s-aws-id`, so a token minted for one cluster cannot be replayed
10
+ // against another. The token is short-lived (~15 min), which is precisely why it can't be a
11
+ // stored static secret and must be minted per use (behind the async `KubernetesTokenProvider`
12
+ // seam in `KubernetesApiClient`).
13
+ //
14
+ // This is implemented with WebCrypto (`crypto.subtle`, HMAC-SHA256 + SHA-256) so it is
15
+ // runtime-neutral (Node + the Cloudflare Worker) and carries NO AWS SDK runtime dependency.
16
+ // The signing is a pure function of its inputs (credentials + region + cluster + timestamp),
17
+ // so it is deterministically golden-vector testable.
18
+ // ---------------------------------------------------------------------------
19
+ const ALGORITHM = 'AWS4-HMAC-SHA256';
20
+ const SERVICE = 'sts';
21
+ const CLUSTER_HEADER = 'x-k8s-aws-id';
22
+ const TOKEN_PREFIX = 'k8s-aws-v1.';
23
+ /** X-Amz-Expires for the presign. 60s is what aws-iam-authenticator uses; the k8s side accepts the token for ~15m. */
24
+ const PRESIGN_EXPIRES_SECONDS = 60;
25
+ /**
26
+ * Mint an EKS apiserver bearer token (`k8s-aws-v1.<base64url(presigned STS URL)>`).
27
+ * Pure + deterministic given `now`.
28
+ */
29
+ export async function mintEksToken(params) {
30
+ const { region, clusterName, credentials } = params;
31
+ const stsHost = params.stsHost ?? `sts.${region}.amazonaws.com`;
32
+ const now = new Date(params.now ?? Date.now());
33
+ const amzDate = toAmzDate(now);
34
+ const dateStamp = amzDate.slice(0, 8);
35
+ const credentialScope = `${dateStamp}/${region}/${SERVICE}/aws4_request`;
36
+ // The presign query params (everything except the signature itself), sorted canonically.
37
+ const query = {
38
+ Action: 'GetCallerIdentity',
39
+ Version: '2011-06-15',
40
+ 'X-Amz-Algorithm': ALGORITHM,
41
+ 'X-Amz-Credential': `${credentials.accessKeyId}/${credentialScope}`,
42
+ 'X-Amz-Date': amzDate,
43
+ 'X-Amz-Expires': String(PRESIGN_EXPIRES_SECONDS),
44
+ 'X-Amz-SignedHeaders': `host;${CLUSTER_HEADER}`,
45
+ };
46
+ if (credentials.sessionToken)
47
+ query['X-Amz-Security-Token'] = credentials.sessionToken;
48
+ const canonicalQuery = canonicalQueryString(query);
49
+ // The cluster name is bound via a SIGNED header — this is what makes the token cluster-scoped.
50
+ const canonicalHeaders = `host:${stsHost}\n${CLUSTER_HEADER}:${clusterName}\n`;
51
+ const signedHeaders = `host;${CLUSTER_HEADER}`;
52
+ // STS is not S3, so a presigned GET with no body hashes the empty string (not UNSIGNED-PAYLOAD).
53
+ const payloadHash = await sha256Hex('');
54
+ const canonicalRequest = [
55
+ 'GET',
56
+ '/',
57
+ canonicalQuery,
58
+ canonicalHeaders,
59
+ signedHeaders,
60
+ payloadHash,
61
+ ].join('\n');
62
+ const stringToSign = [
63
+ ALGORITHM,
64
+ amzDate,
65
+ credentialScope,
66
+ await sha256Hex(canonicalRequest),
67
+ ].join('\n');
68
+ const signingKey = await deriveSigningKey(credentials.secretAccessKey, dateStamp, region);
69
+ const signature = toHex(await hmac(signingKey, stringToSign));
70
+ const presignedUrl = `https://${stsHost}/?${canonicalQuery}&X-Amz-Signature=${signature}`;
71
+ return TOKEN_PREFIX + base64UrlEncode(new TextEncoder().encode(presignedUrl));
72
+ }
73
+ /**
74
+ * Build the async token provider `KubernetesApiClient` calls per request. It reads the AWS
75
+ * credentials from the run's secret bundle and mints a token, caching it briefly so a single
76
+ * transport call (e.g. an apply loop) mints once rather than per apiserver request.
77
+ */
78
+ export function eksTokenProvider(cluster, resolveSecret) {
79
+ // Refresh well before the ~15m server-side acceptance window; a fresh mint is cheap.
80
+ const CACHE_TTL_MS = 10 * 60_000;
81
+ const REFRESH_GUARD_MS = 60_000;
82
+ let cached = null;
83
+ return async () => {
84
+ const now = Date.now();
85
+ if (cached && cached.expiresAt - REFRESH_GUARD_MS > now)
86
+ return cached.token;
87
+ const credentials = readAwsCredentials(resolveSecret);
88
+ const token = await mintEksToken({ ...cluster, credentials, now });
89
+ cached = { token, expiresAt: now + CACHE_TTL_MS };
90
+ return token;
91
+ };
92
+ }
93
+ /** Read the AWS credentials from the encrypted secret bundle. Throws if the required keys are absent. */
94
+ export function readAwsCredentials(resolveSecret) {
95
+ const accessKeyId = resolveSecret(EKS_ACCESS_KEY_ID_SECRET_KEY);
96
+ const secretAccessKey = resolveSecret(EKS_SECRET_ACCESS_KEY_SECRET_KEY);
97
+ if (!accessKeyId || !secretAccessKey) {
98
+ throw new Error(`Missing AWS credentials for EKS ('${EKS_ACCESS_KEY_ID_SECRET_KEY}' / ` +
99
+ `'${EKS_SECRET_ACCESS_KEY_SECRET_KEY}').`);
100
+ }
101
+ const sessionToken = resolveSecret(EKS_SESSION_TOKEN_SECRET_KEY) || undefined;
102
+ return { accessKeyId, secretAccessKey, sessionToken };
103
+ }
104
+ // --- SigV4 primitives (WebCrypto) ------------------------------------------
105
+ /** Format an epoch Date as the SigV4 `YYYYMMDDTHHMMSSZ` basic ISO-8601 timestamp (UTC). */
106
+ function toAmzDate(d) {
107
+ const p = (n) => String(n).padStart(2, '0');
108
+ return (`${d.getUTCFullYear()}${p(d.getUTCMonth() + 1)}${p(d.getUTCDate())}` +
109
+ `T${p(d.getUTCHours())}${p(d.getUTCMinutes())}${p(d.getUTCSeconds())}Z`);
110
+ }
111
+ /** Sort the query params by key and RFC3986-encode both key and value (including `/` in values). */
112
+ function canonicalQueryString(params) {
113
+ return Object.keys(params)
114
+ .sort()
115
+ .map((k) => `${awsUriEncode(k)}=${awsUriEncode(params[k])}`)
116
+ .join('&');
117
+ }
118
+ /** RFC3986 percent-encoding as AWS SigV4 requires (unreserved = A-Za-z0-9-_.~; everything else encoded). */
119
+ function awsUriEncode(value) {
120
+ let out = '';
121
+ for (const byte of new TextEncoder().encode(value)) {
122
+ const isUnreserved = (byte >= 0x41 && byte <= 0x5a) || // A-Z
123
+ (byte >= 0x61 && byte <= 0x7a) || // a-z
124
+ (byte >= 0x30 && byte <= 0x39) || // 0-9
125
+ byte === 0x2d || // -
126
+ byte === 0x2e || // .
127
+ byte === 0x5f || // _
128
+ byte === 0x7e; // ~
129
+ out += isUnreserved
130
+ ? String.fromCharCode(byte)
131
+ : `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
132
+ }
133
+ return out;
134
+ }
135
+ /** The SigV4 signing key: HMAC chain over date → region → service → `aws4_request`. */
136
+ async function deriveSigningKey(secretAccessKey, dateStamp, region) {
137
+ const kDate = await hmac(new TextEncoder().encode(`AWS4${secretAccessKey}`), dateStamp);
138
+ const kRegion = await hmac(kDate, region);
139
+ const kService = await hmac(kRegion, SERVICE);
140
+ return hmac(kService, 'aws4_request');
141
+ }
142
+ async function hmac(key, message) {
143
+ const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
144
+ const sig = await crypto.subtle.sign('HMAC', cryptoKey, new TextEncoder().encode(message));
145
+ return new Uint8Array(sig);
146
+ }
147
+ async function sha256Hex(message) {
148
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(message));
149
+ return toHex(new Uint8Array(digest));
150
+ }
151
+ function toHex(bytes) {
152
+ let out = '';
153
+ for (const b of bytes)
154
+ out += b.toString(16).padStart(2, '0');
155
+ return out;
156
+ }
157
+ /** URL-safe, unpadded base64 (the token envelope EKS expects). */
158
+ function base64UrlEncode(bytes) {
159
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
160
+ let out = '';
161
+ for (let i = 0; i < bytes.length; i += 3) {
162
+ const b0 = bytes[i];
163
+ const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
164
+ const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
165
+ out += chars[b0 >> 2];
166
+ out += chars[((b0 & 0x03) << 4) | (b1 >> 4)];
167
+ if (i + 1 < bytes.length)
168
+ out += chars[((b1 & 0x0f) << 2) | (b2 >> 6)];
169
+ if (i + 2 < bytes.length)
170
+ out += chars[b2 & 0x3f];
171
+ }
172
+ return out;
173
+ }
174
+ //# sourceMappingURL=eks-auth.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-auth.logic.js","sourceRoot":"","sources":["../src/eks-auth.logic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type EnvironmentBackendProvider } from '@cat-factory/integrations';
2
+ export declare const eksEnvironmentBackend: EnvironmentBackendProvider;
3
+ //# sourceMappingURL=eks-environment-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-environment-backend.d.ts","sourceRoot":"","sources":["../src/eks-environment-backend.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,0BAA0B,EAAmB,MAAM,2BAA2B,CAAA;AAkB5F,eAAO,MAAM,qBAAqB,EAAE,0BA4BnC,CAAA"}
@@ -0,0 +1,66 @@
1
+ import { EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY, } from '@cat-factory/contracts';
2
+ import { kubernetesLogic } from '@cat-factory/integrations';
3
+ import { EksEnvironmentProvider } from './EksEnvironmentProvider.js';
4
+ // The AWS EKS ephemeral-environment backend: per-PR namespaces on an EKS cluster, identical to
5
+ // the built-in `kubernetes` backend but authenticated with a minted IAM token. Registered by
6
+ // reference (opt-in) into the app-owned `EnvironmentBackendRegistry`; resolved by `kind` at
7
+ // provision time (`buildFromRecord` → `get('eks')`), so `buildProvider` returns the real
8
+ // `EksEnvironmentProvider`.
9
+ //
10
+ // `engines()` returns `remote-kubernetes` (an EKS cluster IS a remote Kubernetes apiserver).
11
+ // The built-in `kubernetes` backend is registered first, so it still wins `byEngine` — this
12
+ // backend never shadows it and is reached by explicitly pinning `backendKind: 'eks'`. NOTE:
13
+ // surfacing EKS as its OWN first-class engine in the SPA infra-handler selector (so the connect
14
+ // flow lowers to `{ kind: 'eks' }` rather than `{ kind: 'kubernetes' }`) needs a dedicated
15
+ // `InfraEngine('eks')` threaded through the contract engine union + `handlerConfigToBackendConfig`
16
+ // + the SPA forms — a scoped follow-up. The provider itself is fully functional today when
17
+ // resolved by kind (direct/API use and the integration suite construct it directly).
18
+ export const eksEnvironmentBackend = {
19
+ kind: 'eks',
20
+ displayLabel: 'AWS EKS',
21
+ engines: () => ['remote-kubernetes'],
22
+ referencedSecretKeys: (config) => 'eks' in config ? [EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY] : [],
23
+ connectionMeta: (config) => {
24
+ if (!('eks' in config))
25
+ throw new Error('Expected an EKS environment config');
26
+ return {
27
+ providerId: 'eks',
28
+ label: config.eks.label,
29
+ baseUrl: config.eks.apiServerUrl,
30
+ };
31
+ },
32
+ assertConfigSafe: (config, opts) => {
33
+ if (!('eks' in config))
34
+ return;
35
+ kubernetesLogic.assertApiServerUrlSafe(config.eks.apiServerUrl);
36
+ kubernetesLogic.assertCustomTlsSupported(config.eks, opts);
37
+ },
38
+ toManifest: (config) => {
39
+ if (!('eks' in config))
40
+ throw new Error('Expected an EKS environment config');
41
+ return toEksManifest(config.eks);
42
+ },
43
+ fromManifest: (manifest) => ({
44
+ kind: 'eks',
45
+ eks: manifest.providerConfig,
46
+ }),
47
+ buildProvider: (ctx) => new EksEnvironmentProvider({ urlPolicy: ctx.urlPolicy }),
48
+ };
49
+ /** Store the EKS provision config on an EnvironmentManifest (the native adapter ignores the HTTP fields). */
50
+ function toEksManifest(config) {
51
+ return {
52
+ providerId: 'eks',
53
+ label: config.label,
54
+ // The apiserver root; NOT manifest-SSRF-checked (a cluster is routinely a private host) —
55
+ // the backend runs `assertApiServerUrlSafe` instead.
56
+ baseUrl: config.apiServerUrl,
57
+ // Inert for the native adapter (which mints an IAM token), but the manifest schema
58
+ // requires an auth + provision + response; supply placeholders.
59
+ auth: { type: 'bearer', secretRef: { key: EKS_ACCESS_KEY_ID_SECRET_KEY } },
60
+ provision: { method: 'POST', pathTemplate: '' },
61
+ response: {},
62
+ ...(config.defaultTtlMs ? { defaultTtlMs: config.defaultTtlMs } : {}),
63
+ providerConfig: config,
64
+ };
65
+ }
66
+ //# sourceMappingURL=eks-environment-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-environment-backend.js","sourceRoot":"","sources":["../src/eks-environment-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,GAEjC,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAmC,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE5F,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAEpE,+FAA+F;AAC/F,6FAA6F;AAC7F,4FAA4F;AAC5F,yFAAyF;AACzF,4BAA4B;AAC5B,EAAE;AACF,6FAA6F;AAC7F,4FAA4F;AAC5F,4FAA4F;AAC5F,gGAAgG;AAChG,2FAA2F;AAC3F,mGAAmG;AACnG,2FAA2F;AAC3F,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAA+B;IAC/D,IAAI,EAAE,KAAK;IACX,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,mBAAmB,CAAC;IACpC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/B,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,4BAA4B,EAAE,gCAAgC,CAAC,CAAC,CAAC,CAAC,EAAE;IACzF,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE;QACzB,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QAC7E,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK;YACvB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY;SACjC,CAAA;IACH,CAAC;IACD,gBAAgB,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACjC,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,OAAM;QAC9B,eAAe,CAAC,sBAAsB,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC/D,eAAe,CAAC,wBAAwB,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC5D,CAAC;IACD,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;QACrB,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QAC7E,OAAO,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAClC,CAAC;IACD,YAAY,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC3B,IAAI,EAAE,KAAK;QACX,GAAG,EAAE,QAAQ,CAAC,cAA+C;KAC9D,CAAC;IACF,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,sBAAsB,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;CACjF,CAAA;AAED,6GAA6G;AAC7G,SAAS,aAAa,CAAC,MAA0B;IAC/C,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,0FAA0F;QAC1F,qDAAqD;QACrD,OAAO,EAAE,MAAM,CAAC,YAAY;QAC5B,mFAAmF;QACnF,gEAAgE;QAChE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,4BAA4B,EAAE,EAAE;QAC1E,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;QAC/C,QAAQ,EAAE,EAAE;QACZ,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,cAAc,EAAE,MAA4C;KAC7D,CAAA;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ProviderConfigField } from '@cat-factory/kernel';
2
+ /** Non-secret AWS cluster fields (region + cluster name + optional STS host override). */
3
+ export declare const EKS_CLUSTER_FORM_FIELDS: ProviderConfigField[];
4
+ /** AWS credential secrets (access key + secret key required, session token optional). */
5
+ export declare const EKS_CREDENTIAL_FORM_FIELDS: ProviderConfigField[];
6
+ //# sourceMappingURL=eks-form.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-form.logic.d.ts","sourceRoot":"","sources":["../src/eks-form.logic.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAQ9D,0FAA0F;AAC1F,eAAO,MAAM,uBAAuB,EAAE,mBAAmB,EAqBxD,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,EAAE,mBAAmB,EAc3D,CAAA"}
@@ -0,0 +1,46 @@
1
+ import { EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY, EKS_SESSION_TOKEN_SECRET_KEY, } from '@cat-factory/contracts';
2
+ // The EKS-specific flat connect-form fields, shared by the runner + environment backends so the
3
+ // two can't drift. An EKS config is a Kubernetes config (its shared apiserver fields come from
4
+ // `kubernetesLogic.KUBERNETES_RUNNER_FORM_FIELDS`) PLUS these AWS fields: the non-secret
5
+ // region/cluster/STS-host used to mint the IAM apiserver token, and the credential secrets that
6
+ // ride the write-only bundle. The SPA renders them generically — it never knows EKS exists.
7
+ /** Non-secret AWS cluster fields (region + cluster name + optional STS host override). */
8
+ export const EKS_CLUSTER_FORM_FIELDS = [
9
+ {
10
+ key: 'region',
11
+ label: 'AWS region',
12
+ required: true,
13
+ placeholder: 'us-east-1',
14
+ help: 'The cluster region — the regional STS endpoint + the SigV4 credential scope.',
15
+ },
16
+ {
17
+ key: 'clusterName',
18
+ label: 'EKS cluster name',
19
+ required: true,
20
+ placeholder: 'prod',
21
+ help: 'Bound into the presigned STS token via the signed x-k8s-aws-id header.',
22
+ },
23
+ {
24
+ key: 'stsHost',
25
+ label: 'STS host override',
26
+ placeholder: 'sts.us-east-1.amazonaws.com',
27
+ help: 'Set for a VPC/FIPS/GovCloud STS endpoint. Bare host or host:port; defaults to the regional public endpoint.',
28
+ },
29
+ ];
30
+ /** AWS credential secrets (access key + secret key required, session token optional). */
31
+ export const EKS_CREDENTIAL_FORM_FIELDS = [
32
+ { key: EKS_ACCESS_KEY_ID_SECRET_KEY, label: 'AWS access key id', secret: true, required: true },
33
+ {
34
+ key: EKS_SECRET_ACCESS_KEY_SECRET_KEY,
35
+ label: 'AWS secret access key',
36
+ secret: true,
37
+ required: true,
38
+ },
39
+ {
40
+ key: EKS_SESSION_TOKEN_SECRET_KEY,
41
+ label: 'AWS session token',
42
+ secret: true,
43
+ help: 'Only for temporary (STS / assume-role) credentials.',
44
+ },
45
+ ];
46
+ //# sourceMappingURL=eks-form.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-form.logic.js","sourceRoot":"","sources":["../src/eks-form.logic.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,EAChC,4BAA4B,GAC7B,MAAM,wBAAwB,CAAA;AAG/B,gGAAgG;AAChG,+FAA+F;AAC/F,yFAAyF;AACzF,gGAAgG;AAChG,4FAA4F;AAE5F,0FAA0F;AAC1F,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D;QACE,GAAG,EAAE,QAAQ;QACb,KAAK,EAAE,YAAY;QACnB,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,8EAA8E;KACrF;IACD;QACE,GAAG,EAAE,aAAa;QAClB,KAAK,EAAE,kBAAkB;QACzB,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,MAAM;QACnB,IAAI,EAAE,wEAAwE;KAC/E;IACD;QACE,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,6BAA6B;QAC1C,IAAI,EAAE,6GAA6G;KACpH;CACF,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,0BAA0B,GAA0B;IAC/D,EAAE,GAAG,EAAE,4BAA4B,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC/F;QACE,GAAG,EAAE,gCAAgC;QACrC,KAAK,EAAE,uBAAuB;QAC9B,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;KACf;IACD;QACE,GAAG,EAAE,4BAA4B;QACjC,KAAK,EAAE,mBAAmB;QAC1B,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,qDAAqD;KAC5D;CACF,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { type RunnerBackendProvider } from '@cat-factory/integrations';
2
+ export declare const eksRunnerBackend: RunnerBackendProvider;
3
+ //# sourceMappingURL=eks-runner-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-runner-backend.d.ts","sourceRoot":"","sources":["../src/eks-runner-backend.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAcvF,eAAO,MAAM,gBAAgB,EAAE,qBA+C9B,CAAA"}
@@ -0,0 +1,63 @@
1
+ import { EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY, } from '@cat-factory/contracts';
2
+ import { kubernetesLogic } from '@cat-factory/integrations';
3
+ import { EKS_CLUSTER_FORM_FIELDS, EKS_CREDENTIAL_FORM_FIELDS } from './eks-form.logic.js';
4
+ import { EksRunnerTransport } from './EksRunnerTransport.js';
5
+ // The AWS EKS runner backend: native per-run pods on an EKS cluster over the apiserver
6
+ // pod-proxy, exactly like the built-in `kubernetes` backend but authenticated with a minted
7
+ // IAM token instead of a static ServiceAccount token. Registered by reference (opt-in) into the
8
+ // app-owned `RunnerBackendRegistry` from a facade's composition root — the default registry
9
+ // stays AWS-free (see `@cat-factory/integrations` `createBackendRegistries`).
10
+ //
11
+ // Routing is by `kind`, so this backend only ever sees its own `{ kind: 'eks', eks }` config;
12
+ // the structural `'eks' in config` narrowing (not `config.kind === 'eks'`) is used because the
13
+ // open contract union also carries a generic custom member whose `kind` could equal `'eks'`.
14
+ export const eksRunnerBackend = {
15
+ kind: 'eks',
16
+ displayLabel: 'AWS EKS',
17
+ // The typed flat connect form the SPA renders generically — the SAME shared apiserver fields
18
+ // as the native Kubernetes backend PLUS the AWS region/cluster + credential secrets. The
19
+ // config skeleton the flat fields overlay onto is `{ kind: 'eks', eks }`, so the SPA assembles
20
+ // an EKS config without knowing EKS exists (it reads the single payload key off the skeleton).
21
+ form: {
22
+ fields: () => [
23
+ ...kubernetesLogic.KUBERNETES_RUNNER_FORM_FIELDS,
24
+ ...EKS_CLUSTER_FORM_FIELDS,
25
+ ...EKS_CREDENTIAL_FORM_FIELDS,
26
+ ],
27
+ skeleton: () => ({ kind: 'eks', eks: {} }),
28
+ valuesFromConfig: (config) => 'eks' in config
29
+ ? kubernetesLogic.flattenConfigValues(config.eks, [
30
+ ...kubernetesLogic.KUBERNETES_RUNNER_FORM_FIELDS,
31
+ ...EKS_CLUSTER_FORM_FIELDS,
32
+ ])
33
+ : {},
34
+ },
35
+ referencedSecretKeys: (config) => 'eks' in config ? [EKS_ACCESS_KEY_ID_SECRET_KEY, EKS_SECRET_ACCESS_KEY_SECRET_KEY] : [],
36
+ connectionMeta: (config) => {
37
+ if (!('eks' in config))
38
+ throw new Error('Expected an EKS runner config');
39
+ return {
40
+ providerId: 'eks',
41
+ label: config.eks.label,
42
+ baseUrl: config.eks.apiServerUrl,
43
+ };
44
+ },
45
+ assertConfigSafe: (config, opts) => {
46
+ if (!('eks' in config))
47
+ return;
48
+ kubernetesLogic.assertApiServerUrlSafe(config.eks.apiServerUrl);
49
+ kubernetesLogic.assertCustomTlsSupported(config.eks, opts);
50
+ },
51
+ buildTransport: (config, ctx) => {
52
+ if (!('eks' in config))
53
+ throw new Error('Expected an EKS runner config');
54
+ return new EksRunnerTransport(config.eks, ctx.resolveSecret);
55
+ },
56
+ testConnection: (config, ctx) => {
57
+ if (!('eks' in config)) {
58
+ return Promise.resolve({ ok: false, message: 'Expected an EKS runner config' });
59
+ }
60
+ return new EksRunnerTransport(config.eks, ctx.resolveSecret).testConnection();
61
+ },
62
+ };
63
+ //# sourceMappingURL=eks-runner-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eks-runner-backend.js","sourceRoot":"","sources":["../src/eks-runner-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,eAAe,EAA8B,MAAM,2BAA2B,CAAA;AAEvF,OAAO,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAA;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,uFAAuF;AACvF,4FAA4F;AAC5F,gGAAgG;AAChG,4FAA4F;AAC5F,8EAA8E;AAC9E,EAAE;AACF,8FAA8F;AAC9F,+FAA+F;AAC/F,6FAA6F;AAC7F,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,IAAI,EAAE,KAAK;IACX,YAAY,EAAE,SAAS;IACvB,6FAA6F;IAC7F,yFAAyF;IACzF,+FAA+F;IAC/F,+FAA+F;IAC/F,IAAI,EAAE;QACJ,MAAM,EAAE,GAAG,EAAE,CAAC;YACZ,GAAG,eAAe,CAAC,6BAA6B;YAChD,GAAG,uBAAuB;YAC1B,GAAG,0BAA0B;SAC9B;QACD,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAwB;QACjE,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC3B,KAAK,IAAI,MAAM;YACb,CAAC,CAAC,eAAe,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAyC,EAAE;gBACpF,GAAG,eAAe,CAAC,6BAA6B;gBAChD,GAAG,uBAAuB;aAC3B,CAAC;YACJ,CAAC,CAAC,EAAE;KACT;IACD,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/B,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,4BAA4B,EAAE,gCAAgC,CAAC,CAAC,CAAC,CAAC,EAAE;IACzF,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE;QACzB,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;QACxE,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK;YACvB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY;SACjC,CAAA;IACH,CAAC;IACD,gBAAgB,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACjC,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,OAAM;QAC9B,eAAe,CAAC,sBAAsB,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC/D,eAAe,CAAC,wBAAwB,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC5D,CAAC;IACD,cAAc,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QAC9B,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;QACxE,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,aAAa,CAAC,CAAA;IAC9D,CAAC;IACD,cAAc,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QAC9B,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC;YACvB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,CAAA;QACjF,CAAC;QACD,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,cAAc,EAAE,CAAA;IAC/E,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { eksRunnerBackend } from './eks-runner-backend.js';
2
+ export { eksEnvironmentBackend } from './eks-environment-backend.js';
3
+ export { EksRunnerTransport } from './EksRunnerTransport.js';
4
+ export { EksEnvironmentProvider } from './EksEnvironmentProvider.js';
5
+ export { mintEksToken, eksTokenProvider, readAwsCredentials, type MintEksTokenParams, type EksAwsCredentials, } from './eks-auth.logic.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // Public surface of the opt-in AWS EKS backend package.
2
+ //
3
+ // An EKS cluster's apiserver is a standard Kubernetes apiserver, so this package REUSES the
4
+ // native Kubernetes transport/provider from `@cat-factory/integrations` and only supplies the
5
+ // EKS differentiator: a SigV4-presigned STS (IAM) apiserver token minted per use. A deployment
6
+ // opts in by registering the two backends BY REFERENCE into the app-owned registries from its
7
+ // composition root (the default registries stay AWS-free):
8
+ //
9
+ // import { eksRunnerBackend, eksEnvironmentBackend } from '@cat-factory/eks'
10
+ // registries.runnerBackendRegistry.register(eksRunnerBackend)
11
+ // registries.environmentBackendRegistry.register(eksEnvironmentBackend)
12
+ export { eksRunnerBackend } from './eks-runner-backend.js';
13
+ export { eksEnvironmentBackend } from './eks-environment-backend.js';
14
+ export { EksRunnerTransport } from './EksRunnerTransport.js';
15
+ export { EksEnvironmentProvider } from './EksEnvironmentProvider.js';
16
+ export { mintEksToken, eksTokenProvider, readAwsCredentials, } from './eks-auth.logic.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,8FAA8F;AAC9F,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,gEAAgE;AAChE,0EAA0E;AAE1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,GAGnB,MAAM,qBAAqB,CAAA"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@cat-factory/eks",
3
+ "version": "0.0.0",
4
+ "description": "Opt-in AWS EKS runner + environment backends for cat-factory. Reuses the native Kubernetes transport/provider behind a SigV4-presigned STS (IAM) apiserver token.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/kibertoad/cat-factory.git",
8
+ "directory": "backend/packages/eks"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "dependencies": {
27
+ "@cat-factory/contracts": "0.97.0",
28
+ "@cat-factory/integrations": "0.65.3",
29
+ "@cat-factory/kernel": "0.88.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^26.0.1",
33
+ "typescript": "7.0.1-rc",
34
+ "valibot": "^1.4.2",
35
+ "vitest": "^4.1.9"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -b tsconfig.build.json",
39
+ "typecheck": "tsc -p tsconfig.json --noEmit",
40
+ "test": "vitest run",
41
+ "test:run": "vitest run",
42
+ "test:integration": "vitest run -c vitest.integration.config.ts"
43
+ }
44
+ }