@intentius/chant-k8s-client 0.31.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.
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The chant Kubernetes API client — chant #1074.
3
+ *
4
+ * ## What is rented and what is chant's
5
+ *
6
+ * `@kubernetes/client-node` supplies transport and authentication: kubeconfig
7
+ * parsing and merging, client certificates, bearer tokens, exec credential
8
+ * plugins with expiry-aware caching, in-cluster service-account credentials,
9
+ * TLS (CA bundles, `insecure-skip-tls-verify`, `tls-server-name`), HTTP and
10
+ * SOCKS proxies, and impersonation. That work is done, maintained, and
11
+ * security-sensitive; reimplementing it buys nothing.
12
+ *
13
+ * Chant supplies the rest: resource resolution through the cluster's own
14
+ * discovery (rather than a table someone has to keep extending), bounded
15
+ * concurrency, typed failures, an exec-plugin allowlist, and credential
16
+ * provenance.
17
+ *
18
+ * ## Raw objects, not deserialized models
19
+ *
20
+ * The library also ships `KubernetesObjectApi`, which does path construction
21
+ * and discovery. It is not used, for one reason: it runs every response
22
+ * through `ObjectSerializer`, which coerces known kinds into generated model
23
+ * classes — dropping fields the model does not declare and turning timestamps
24
+ * into `Date`s — while passing CRDs through raw. An observation path must not
25
+ * behave differently for a Deployment and a RayCluster, and `managedFields`
26
+ * (the epic's whole point, chant #1076) is exactly the sort of field a model
27
+ * coercion loses. So requests are issued against the library's `RequestContext`
28
+ * and the JSON is used as it arrived.
29
+ *
30
+ * ## The one seam
31
+ *
32
+ * `requestLayer` replaces the library's HTTP send and nothing else. Everything
33
+ * above it — kubeconfig parsing, context selection, URL construction, the auth
34
+ * path that writes the `Authorization` header — runs for real, which is what
35
+ * makes a test that injects one worth writing.
36
+ */
37
+ import type { ApiResourceInfo, ClientProvenance, K8sClientOptions, K8sObject, ObjectRef, ResourceSelector } from "./types.js";
38
+ type ClientNode = typeof import("@kubernetes/client-node");
39
+ /**
40
+ * Load `@kubernetes/client-node`, once per process.
41
+ *
42
+ * Deliberately a function, not a module-level `await import`: this package is
43
+ * an optional dependency reached only from chant's read/write paths, and
44
+ * resolving it at module load would defeat that. Nothing here touches the
45
+ * filesystem at module init either (chant #1081).
46
+ */
47
+ export declare function loadClientNode(): Promise<ClientNode>;
48
+ /** True when `@kubernetes/client-node` can be loaded in this install. */
49
+ export declare function isK8sClientAvailable(): Promise<boolean>;
50
+ /**
51
+ * The kubeconfig's own current-context, without building a client.
52
+ *
53
+ * This is what the environment→cluster binding compares against (chant #1100):
54
+ * "the ambient context" is a property of the kubeconfig, and reading it should
55
+ * not require the kubeconfig to also resolve to a usable cluster — a binding
56
+ * pointing at a valid context has to survive a broken current-context, which is
57
+ * exactly the situation the binding exists to fix. Returns undefined when no
58
+ * kubeconfig can be read at all.
59
+ */
60
+ export declare function readAmbientContext(options?: Pick<K8sClientOptions, "kubeconfig" | "kubeconfigPath">): Promise<string | undefined>;
61
+ /** Options for a single object read. */
62
+ export interface ReadOptions {
63
+ signal?: AbortSignal;
64
+ }
65
+ /** Options for {@link K8sClient.apply}. */
66
+ export interface ApplyOptions {
67
+ /** Field manager recorded on the objects this apply owns. Default `chant`. */
68
+ fieldManager?: string;
69
+ /**
70
+ * Take ownership of fields another manager owns instead of failing with a
71
+ * 409. Default false — chant #1075 is where the conflict surface proper
72
+ * lives; here a conflict simply arrives as a typed {@link K8sApiError}.
73
+ */
74
+ force?: boolean;
75
+ /** Server-side dry run — validates and returns the result, persists nothing. */
76
+ dryRun?: boolean;
77
+ signal?: AbortSignal;
78
+ }
79
+ /** The client surface the k8s lexicon consumes. */
80
+ export interface K8sClient {
81
+ /** Where this client is pointed and what authorized it. */
82
+ readonly provenance: ClientProvenance;
83
+ /** Namespace the resolved context defaults to. */
84
+ readonly defaultNamespace: string;
85
+ /**
86
+ * Resolve a selector against the cluster's API discovery. Returns undefined
87
+ * when discovery answered and reported no such resource — which means no
88
+ * instance of it can exist.
89
+ */
90
+ resolve(selector: ResourceSelector, signal?: AbortSignal): Promise<ApiResourceInfo | undefined>;
91
+ /** GET one object. Throws {@link K8sApiError} with `notFound` when absent. */
92
+ read(ref: ObjectRef, options?: ReadOptions): Promise<K8sObject>;
93
+ /** GET one object, returning undefined instead of throwing on a 404. */
94
+ readIfPresent(ref: ObjectRef, options?: ReadOptions): Promise<K8sObject | undefined>;
95
+ /** LIST a kind, optionally namespaced. Follows `continue` tokens. */
96
+ list(selector: ResourceSelector, options?: {
97
+ namespace?: string;
98
+ signal?: AbortSignal;
99
+ }): Promise<K8sObject[]>;
100
+ /** Server-side apply one object. Creates it when absent. */
101
+ apply(object: K8sObject, options?: ApplyOptions): Promise<K8sObject>;
102
+ /** Run `fn` over `items` with this client's concurrency ceiling. */
103
+ concurrently<T, R>(items: readonly T[], fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
104
+ /** The API resource lists discovery has been asked for so far, for tests and diagnostics. */
105
+ discoveryCacheKeys(): string[];
106
+ }
107
+ /**
108
+ * Build a client. Nothing is read from the network here — the kubeconfig is
109
+ * parsed, the context resolved, and the credential policy enforced, all before
110
+ * the first request, so a refusal happens before any exec plugin runs.
111
+ */
112
+ export declare function createK8sClient(options?: K8sClientOptions): Promise<K8sClient>;
113
+ /** `v1` → `/api/v1`; `apps/v1` → `/apis/apps/v1`. */
114
+ export declare function apiVersionPath(apiVersion: string): string;
115
+ /** `apps/v1` → `["apps", "v1"]`; `v1` → `["", "v1"]`. */
116
+ export declare function splitApiVersion(apiVersion: string): [group: string, version: string];
117
+ /** Human phrasing of a selector, for error messages. */
118
+ export declare function selectorText(selector: ResourceSelector): string;
119
+ /** Human phrasing of an object reference, for error messages. */
120
+ export declare function refText(ref: ObjectRef): string;
121
+ export {};
122
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Bounded concurrency — chant #1074's "a 100-entity project is not 100 serial
3
+ * spawns" criterion.
4
+ *
5
+ * Unbounded is not the answer either: firing 400 requests at an API server in
6
+ * one tick gets the client throttled (429) or the apiserver's priority-and-
7
+ * fairness queue drops it, and both look like read failures rather than what
8
+ * they are. A small fixed window is what `kubectl` itself uses for parallel
9
+ * gets.
10
+ */
11
+ /** Default in-flight request ceiling. */
12
+ export declare const DEFAULT_CONCURRENCY = 8;
13
+ /**
14
+ * Map `items` through `fn` with at most `limit` running at once, preserving
15
+ * input order in the result. Never rejects: `fn`'s own rejections are the
16
+ * caller's to model (the observation path turns each into a per-entity
17
+ * verdict), so `fn` is expected to resolve with a discriminated outcome.
18
+ */
19
+ export declare function mapConcurrent<T, R>(items: readonly T[], fn: (item: T, index: number) => Promise<R>, limit?: number): Promise<R[]>;
20
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yCAAyC;AACzC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,CAAC,EAAE,CAAC,EACtC,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,KAAK,GAAE,MAA4B,GAClC,OAAO,CAAC,CAAC,EAAE,CAAC,CAed"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Credential policy — chant #1074's managed-cluster half.
3
+ *
4
+ * On EKS, AKS and GKE, kubeconfig authentication is an **exec credential
5
+ * plugin**: `aws eks get-token`, `kubelogin`, `gke-gcloud-auth-plugin`. So on
6
+ * the clusters most people actually run, a "native" client still spawns a
7
+ * process — once per token instead of once per resource read. That is still
8
+ * the win the issue is after, but it is worth stating rather than implying,
9
+ * because an exec plugin runs an arbitrary binary named in a file chant did
10
+ * not write.
11
+ *
12
+ * Three things are chant's to decide, and they live here:
13
+ *
14
+ * 1. **Allowlist.** The plugin's command must be on a list, not merely present
15
+ * in the kubeconfig. The default covers the three managed providers.
16
+ * 2. **Caching.** `@kubernetes/client-node`'s `ExecAuth` caches a credential
17
+ * until its `expirationTimestamp`, keyed by kubeconfig user. The client
18
+ * builds one `KubeConfig` per session and reuses it for every request, so a
19
+ * 200-entity observation invokes `aws eks get-token` once rather than 200
20
+ * times. That is a property of not rebuilding the config, so it is asserted
21
+ * in this package's tests rather than reimplemented here.
22
+ * 3. **Provenance.** Which credential path authorized a read is recorded on
23
+ * the client and travels with the observation.
24
+ */
25
+ import type { CredentialPath } from "./types.js";
26
+ /**
27
+ * Exec credential plugins chant will execute without being asked twice.
28
+ *
29
+ * The three managed-Kubernetes providers plus `kubectl`, which is what
30
+ * `kubectl config set-credentials --exec-command` writes for OIDC setups that
31
+ * shell back through the binary the user already trusts. Anything else has to
32
+ * be named explicitly in `k8s.execCredentialPlugins`.
33
+ */
34
+ export declare const DEFAULT_EXEC_ALLOWLIST: readonly string[];
35
+ /** The exec stanza of a kubeconfig user, as far as this module cares. */
36
+ export interface ExecConfig {
37
+ command?: string;
38
+ args?: string[];
39
+ env?: Array<{
40
+ name: string;
41
+ value: string;
42
+ }>;
43
+ }
44
+ /** The kubeconfig user fields this module reads. */
45
+ export interface KubeConfigUser {
46
+ name?: string;
47
+ exec?: ExecConfig;
48
+ authProvider?: {
49
+ name?: string;
50
+ config?: {
51
+ exec?: ExecConfig;
52
+ };
53
+ };
54
+ token?: string;
55
+ certData?: string;
56
+ certFile?: string;
57
+ username?: string;
58
+ password?: string;
59
+ }
60
+ /**
61
+ * The exec stanza this user authenticates with, if any. `authProvider` can
62
+ * carry one too — client-node's `ExecAuth.isAuthProvider` accepts both shapes,
63
+ * so the gate has to look in both places or it is trivially bypassed.
64
+ */
65
+ export declare function execConfigOf(user: KubeConfigUser | null | undefined): ExecConfig | undefined;
66
+ /**
67
+ * Reduce a plugin command to the name that is allowlisted: `aws` for `aws`,
68
+ * for `/usr/local/bin/aws`, and for `C:\\tools\\aws.exe`. Matching the bare
69
+ * name rather than the full path is deliberate — the path varies per machine,
70
+ * and pinning it would make the allowlist unusable — but it does mean the
71
+ * allowlist expresses "which tool", not "which file".
72
+ */
73
+ export declare function execCommandName(command: string): string;
74
+ /**
75
+ * Throw unless the user's exec plugin (if it has one) is allowlisted. Called
76
+ * before the client issues its first request, so a refusal happens before any
77
+ * binary runs — the check is worthless if it fires after the spawn.
78
+ */
79
+ export declare function assertExecCredentialAllowed(user: KubeConfigUser | null | undefined, allowlist?: readonly string[]): void;
80
+ /** Which credential path a kubeconfig user represents, for provenance. */
81
+ export declare function credentialPathOf(user: KubeConfigUser | null | undefined): {
82
+ credential: CredentialPath;
83
+ execCommand?: string;
84
+ };
85
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAMnD,CAAC;AAEF,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,UAAU,CAAA;SAAE,CAAA;KAAE,CAAC;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAM5F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACvC,SAAS,GAAE,SAAS,MAAM,EAA2B,GACpD,IAAI,CAMN;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG;IACzE,UAAU,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAQA"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Typed failures — chant #1074.
3
+ *
4
+ * The kubectl path this client replaces reported failures as a non-zero exit
5
+ * plus a line of English on stderr, which every caller then had to pattern
6
+ * match (`classifyKubectlFailure` in core is that pattern matcher). The API
7
+ * server already sends a machine-readable `Status` object with a numeric code
8
+ * and a `reason` enum; these errors carry it through instead of re-deriving it
9
+ * from prose.
10
+ */
11
+ /** The `Status` object a Kubernetes API server returns on a failed request. */
12
+ export interface K8sStatus {
13
+ kind?: string;
14
+ apiVersion?: string;
15
+ status?: string;
16
+ message?: string;
17
+ /** e.g. "NotFound", "Forbidden", "Unauthorized", "Conflict", "AlreadyExists". */
18
+ reason?: string;
19
+ code?: number;
20
+ details?: unknown;
21
+ }
22
+ /**
23
+ * The API server answered, and the answer was a failure. `statusCode` and
24
+ * `reason` come from the response, not from parsing text.
25
+ */
26
+ export declare class K8sApiError extends Error {
27
+ readonly statusCode: number;
28
+ readonly reason: string | undefined;
29
+ readonly apiMessage: string;
30
+ /** What was being addressed, e.g. `apps/v1 Deployment prod/web`. */
31
+ readonly target?: string | undefined;
32
+ readonly status?: K8sStatus | undefined;
33
+ constructor(statusCode: number, reason: string | undefined, apiMessage: string,
34
+ /** What was being addressed, e.g. `apps/v1 Deployment prod/web`. */
35
+ target?: string | undefined, status?: K8sStatus | undefined);
36
+ /** The object is not there. The only failure that establishes absence. */
37
+ get notFound(): boolean;
38
+ /** RBAC denied the read. Proves nothing about whether the object exists. */
39
+ get forbidden(): boolean;
40
+ /** No usable credentials for this cluster. */
41
+ get unauthorized(): boolean;
42
+ /** Server-side-apply field-ownership conflict (chant #1075 surfaces these properly). */
43
+ get conflict(): boolean;
44
+ /**
45
+ * Build from a raw response body, which is a `Status` on every well-behaved
46
+ * Kubernetes error and occasionally plain text from a proxy in front of one.
47
+ */
48
+ static fromResponse(statusCode: number, body: string, target?: string): K8sApiError;
49
+ }
50
+ /**
51
+ * The request never reached an API server — DNS, TCP, TLS, proxy, or an
52
+ * aborted signal. Distinct from {@link K8sApiError} because "I could not
53
+ * connect" and "the server said no" are different observations.
54
+ */
55
+ export declare class K8sTransportError extends Error {
56
+ readonly target?: string | undefined;
57
+ constructor(message: string, target?: string | undefined, options?: {
58
+ cause?: unknown;
59
+ });
60
+ }
61
+ /**
62
+ * `@kubernetes/client-node` is not installed. It is an ordinary dependency of
63
+ * this package, so this only happens when the package tree was pruned
64
+ * (`npm install --omit=optional`, a slimmed container image). Named separately
65
+ * so the k8s lexicon can tell a missing dependency from a broken cluster.
66
+ */
67
+ export declare class K8sClientUnavailableError extends Error {
68
+ constructor(cause?: unknown);
69
+ }
70
+ /**
71
+ * The kubeconfig names an exec credential plugin that is not on the allowlist.
72
+ *
73
+ * An exec plugin is an arbitrary binary named in a file chant did not write,
74
+ * run with the CLI's privileges. EKS/AKS/GKE all need one, so refusing them
75
+ * outright would make this client useless on managed clusters — but executing
76
+ * whatever the file names is not a default worth having either.
77
+ */
78
+ export declare class ExecCredentialNotAllowedError extends Error {
79
+ readonly command: string;
80
+ readonly allowed: readonly string[];
81
+ constructor(command: string, allowed: readonly string[]);
82
+ }
83
+ /** The kubeconfig could not be read, or names no usable cluster/context. */
84
+ export declare class KubeConfigError extends Error {
85
+ constructor(message: string);
86
+ }
87
+ /**
88
+ * The cluster's own discovery does not serve this kind. Distinct from a 404 on
89
+ * an instance: no instance of an unserved kind can exist, which is a real
90
+ * absence rather than an unread hole.
91
+ */
92
+ export declare class UnknownResourceError extends Error {
93
+ readonly selectorText: string;
94
+ constructor(selectorText: string, message?: string);
95
+ }
96
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAElB,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM,GAAG,SAAS;aAC1B,UAAU,EAAE,MAAM;IAClC,oEAAoE;aACpD,MAAM,CAAC,EAAE,MAAM;aACf,MAAM,CAAC,EAAE,SAAS;gBALlB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,UAAU,EAAE,MAAM;IAClC,oEAAoE;IACpD,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,MAAM,CAAC,EAAE,SAAS,YAAA;IASpC,0EAA0E;IAC1E,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,4EAA4E;IAC5E,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,8CAA8C;IAC9C,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,wFAAwF;IACxF,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW;CAapF;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;aAGxB,MAAM,CAAC,EAAE,MAAM;gBAD/B,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EAC/B,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAMhC;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,CAAC,EAAE,OAAO;CAS5B;AAED;;;;;;;GAOG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;aAEpC,OAAO,EAAE,MAAM;aACf,OAAO,EAAE,SAAS,MAAM,EAAE;gBAD1B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,SAAS,MAAM,EAAE;CAU7C;AAED,4EAA4E;AAC5E,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM,EACpC,OAAO,CAAC,EAAE,MAAM;CAKnB"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `@intentius/chant-k8s-client` — the typed Kubernetes API client behind the
3
+ * k8s lexicon's read and write paths (chant #1074, epic #1073).
4
+ *
5
+ * It is a package rather than a directory inside the lexicon for one reason:
6
+ * this is the first chant code that holds live cluster credentials, and the
7
+ * synthesis-purity boundary around it should be structural rather than a lint
8
+ * rule. `chant build` cannot resolve this package, because nothing on the
9
+ * build path imports it — the lexicon reaches it through a dynamic import from
10
+ * modules that are themselves only loaded by the observation and Op paths, and
11
+ * `examples/k8s-client-boundary.test.ts` walks the static import graph to prove
12
+ * it stays that way.
13
+ */
14
+ export { createK8sClient, readAmbientContext, loadClientNode, isK8sClientAvailable, apiVersionPath, splitApiVersion, selectorText, refText, } from "./client.js";
15
+ export type { K8sClient, ReadOptions, ApplyOptions } from "./client.js";
16
+ export { K8sApiError, K8sTransportError, K8sClientUnavailableError, ExecCredentialNotAllowedError, KubeConfigError, UnknownResourceError, } from "./errors.js";
17
+ export type { K8sStatus } from "./errors.js";
18
+ export { DEFAULT_EXEC_ALLOWLIST, assertExecCredentialAllowed, credentialPathOf, execConfigOf, execCommandName, } from "./credentials.js";
19
+ export type { ExecConfig, KubeConfigUser } from "./credentials.js";
20
+ export { mapConcurrent, DEFAULT_CONCURRENCY } from "./concurrency.js";
21
+ export type { ApiResourceInfo, ClientProvenance, CredentialPath, K8sClientOptions, K8sObject, ObjectRef, RequestContextLike, RequestLayer, ResourceSelector, ResponseContextLike, } from "./types.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,OAAO,GACR,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,6BAA6B,EAC7B,eAAe,EACf,oBAAoB,GACrB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,gBAAgB,EAChB,YAAY,EACZ,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEnE,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Test doubles for the one seam this package exposes.
3
+ *
4
+ * A fake here replaces `@kubernetes/client-node`'s HTTP send and nothing
5
+ * above it: the handler receives the real, fully built request — the URL the
6
+ * client constructed from discovery, the method, and the headers the
7
+ * kubeconfig's auth path wrote, `Authorization` included. So a test that uses
8
+ * it still exercises kubeconfig parsing, context selection, credential policy,
9
+ * discovery and path construction for real.
10
+ *
11
+ * It exists in the shipped package rather than in a test helper because both
12
+ * this package's tests and the k8s lexicon's tests need it, and because a
13
+ * consumer wiring chant into their own harness needs the same thing.
14
+ */
15
+ import type { RequestLayer } from "./types.js";
16
+ /** What a {@link FakeRequestHandler} sees. */
17
+ export interface RecordedRequest {
18
+ method: string;
19
+ /** Full URL including query string. */
20
+ url: string;
21
+ /** Path only, query stripped. */
22
+ path: string;
23
+ query: Record<string, string>;
24
+ headers: Record<string, string>;
25
+ body: unknown;
26
+ }
27
+ /** What a handler returns. `body` is stringified when it is not already a string. */
28
+ export interface FakeResponse {
29
+ status?: number;
30
+ body?: unknown;
31
+ headers?: Record<string, string>;
32
+ }
33
+ export type FakeRequestHandler = (request: RecordedRequest) => FakeResponse | Promise<FakeResponse>;
34
+ /** A recording {@link RequestLayer} driven by `handler`. */
35
+ export interface FakeRequestLayer extends RequestLayer {
36
+ /** Every request the client issued, in order. */
37
+ readonly requests: RecordedRequest[];
38
+ /** Paths only, in order — the usual assertion target. */
39
+ paths(): string[];
40
+ }
41
+ /**
42
+ * Build a fake request layer. Anything the handler does not answer 200s with
43
+ * an empty object, so a test only has to describe the responses it cares about.
44
+ */
45
+ export declare function fakeRequestLayer(handler: FakeRequestHandler): FakeRequestLayer;
46
+ /** A Kubernetes `Status` failure body, for driving typed-error assertions. */
47
+ export declare function statusBody(code: number, reason: string, message: string): Record<string, unknown>;
48
+ /** Options for {@link fakeKubeconfig}. */
49
+ export interface FakeKubeconfigOptions {
50
+ contexts?: Array<{
51
+ name: string;
52
+ cluster?: string;
53
+ user?: string;
54
+ namespace?: string;
55
+ }>;
56
+ currentContext?: string;
57
+ server?: string;
58
+ /** Static bearer token. Mutually exclusive with `exec` in practice. */
59
+ token?: string;
60
+ /** An exec credential plugin stanza, for allowlist and caching tests. */
61
+ exec?: {
62
+ command: string;
63
+ args?: string[];
64
+ env?: Array<{
65
+ name: string;
66
+ value: string;
67
+ }>;
68
+ };
69
+ }
70
+ /**
71
+ * A literal kubeconfig, so no test ever reads the developer's real one. Every
72
+ * test in this repo that builds a client passes one of these.
73
+ */
74
+ export declare function fakeKubeconfig(options?: FakeKubeconfigOptions): string;
75
+ /** An `APIResourceList` body, the discovery response the client resolves against. */
76
+ export declare function apiResourceList(groupVersion: string, resources: Array<{
77
+ name: string;
78
+ kind: string;
79
+ namespaced?: boolean;
80
+ singularName?: string;
81
+ shortNames?: string[];
82
+ verbs?: string[];
83
+ }>): Record<string, unknown>;
84
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAsB,YAAY,EAAuB,MAAM,SAAS,CAAC;AAErF,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAEpG,4DAA4D;AAC5D,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IACrC,yDAAyD;IACzD,KAAK,IAAI,MAAM,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,gBAAgB,CA8B9E;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUjG;AAED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CAC3F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAkD1E;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,KAAK,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,GACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Public data shapes for the chant Kubernetes API client (chant #1074).
3
+ *
4
+ * Everything here is plain data: no class, nothing imported from
5
+ * `@kubernetes/client-node`, nothing imported from chant core. The lexicon
6
+ * that consumes this package must be able to name these types without pulling
7
+ * either dependency onto the build path.
8
+ */
9
+ /** A live Kubernetes object, as the API server returned it. */
10
+ export interface K8sObject {
11
+ apiVersion?: string;
12
+ kind?: string;
13
+ metadata?: {
14
+ name?: string;
15
+ namespace?: string;
16
+ uid?: string;
17
+ resourceVersion?: string;
18
+ generation?: number;
19
+ creationTimestamp?: string;
20
+ labels?: Record<string, string>;
21
+ annotations?: Record<string, string>;
22
+ ownerReferences?: Array<Record<string, unknown>>;
23
+ managedFields?: Array<Record<string, unknown>>;
24
+ [k: string]: unknown;
25
+ };
26
+ status?: Record<string, unknown>;
27
+ [k: string]: unknown;
28
+ }
29
+ /** Addresses one object. `namespace` is ignored for cluster-scoped kinds. */
30
+ export interface ObjectRef {
31
+ apiVersion: string;
32
+ kind: string;
33
+ name: string;
34
+ namespace?: string;
35
+ }
36
+ /**
37
+ * How to find a resource in the cluster's discovery.
38
+ *
39
+ * - By GVK — what `describeResources` uses, because the generated operation
40
+ * surface gives it an exact `apiVersion` + `kind`.
41
+ * - By kubectl-style resource string — what `waitForReady` uses, because its
42
+ * activity contract has always taken `kind` in the form `kubectl get`
43
+ * accepts (`certificates`, `raycluster.ray.io`, `Deployment`).
44
+ */
45
+ export type ResourceSelector = {
46
+ apiVersion: string;
47
+ kind: string;
48
+ } | {
49
+ resource: string;
50
+ group?: string;
51
+ };
52
+ /** One entry of an `APIResourceList`, as the cluster reports it. */
53
+ export interface ApiResourceInfo {
54
+ /** Plural path segment, e.g. `deployments`. */
55
+ name: string;
56
+ singularName?: string;
57
+ kind: string;
58
+ namespaced: boolean;
59
+ verbs: readonly string[];
60
+ shortNames?: readonly string[];
61
+ /** `""` for the core group. */
62
+ group: string;
63
+ version: string;
64
+ /** `v1` or `apps/v1` — what goes in a manifest. */
65
+ apiVersion: string;
66
+ }
67
+ /** Which credential path the client is authenticating with. */
68
+ export type CredentialPath = "exec-plugin" | "auth-provider" | "token" | "client-certificate" | "basic-auth" | "in-cluster" | "none";
69
+ /**
70
+ * Where an observation's credentials came from, recorded so the provenance of
71
+ * a read is legible (chant #1074's managed-cluster note). A read authorized by
72
+ * `aws eks get-token` and a read authorized by a static service-account token
73
+ * are not equally trustworthy inputs to a drift report.
74
+ */
75
+ export interface ClientProvenance {
76
+ /** API server URL. */
77
+ server: string;
78
+ /** kubectl context the client resolved to. */
79
+ context?: string;
80
+ /** Where the context came from — a declared binding or the ambient default. */
81
+ contextSource: "bound" | "ambient";
82
+ credential: CredentialPath;
83
+ /** The exec plugin's command, when `credential` is `exec-plugin`. */
84
+ execCommand?: string;
85
+ /** Where the kubeconfig itself came from. */
86
+ kubeconfigSource: "explicit-string" | "explicit-path" | "default" | "in-cluster";
87
+ }
88
+ /** Options for {@link import("./client.js").createK8sClient}. */
89
+ export interface K8sClientOptions {
90
+ /**
91
+ * Literal kubeconfig YAML. Wins over every other source — which is how
92
+ * tests avoid reading the developer's real `~/.kube/config`.
93
+ */
94
+ kubeconfig?: string;
95
+ /** Path to a kubeconfig file. Wins over the ambient default. */
96
+ kubeconfigPath?: string;
97
+ /**
98
+ * Context to use, from `k8s.profiles.<env>.context` (chant #1100/#1155).
99
+ * Omitted means the kubeconfig's own current-context.
100
+ */
101
+ context?: string;
102
+ /**
103
+ * Exec credential-plugin commands this client may execute. Defaults to
104
+ * {@link import("./credentials.js").DEFAULT_EXEC_ALLOWLIST}.
105
+ */
106
+ execAllowlist?: readonly string[];
107
+ /**
108
+ * Replaces `@kubernetes/client-node`'s HTTP send. This is the package's only
109
+ * seam onto the network: URL construction, kubeconfig parsing, auth header
110
+ * application and response handling all still run for real above it. Tests
111
+ * pass one; production does not.
112
+ */
113
+ requestLayer?: RequestLayer;
114
+ /** Max concurrent in-flight requests. Default 8. */
115
+ concurrency?: number;
116
+ /** Where the context came from, for provenance. Default `ambient`. */
117
+ contextSource?: "bound" | "ambient";
118
+ }
119
+ /**
120
+ * `@kubernetes/client-node`'s promise-shaped HTTP library: it receives the
121
+ * library's own `RequestContext` (fully built URL, method, headers including
122
+ * whatever the auth path put there) and returns its own `ResponseContext`.
123
+ *
124
+ * Typed structurally rather than against the library's classes so this module
125
+ * stays free of `@kubernetes/client-node` imports; `client.ts` checks the real
126
+ * shapes where it matters.
127
+ */
128
+ export interface RequestLayer {
129
+ send(request: RequestContextLike): Promise<ResponseContextLike> | ResponseContextLike;
130
+ }
131
+ /** The subset of client-node's `RequestContext` this package and its tests read. */
132
+ export interface RequestContextLike {
133
+ getUrl(): string;
134
+ getHttpMethod(): string;
135
+ getHeaders(): Record<string, string>;
136
+ getBody(): unknown;
137
+ }
138
+ /** The subset of client-node's `ResponseContext` this package produces and consumes. */
139
+ export interface ResponseContextLike {
140
+ httpStatusCode: number;
141
+ headers: Record<string, string>;
142
+ body: {
143
+ text(): Promise<string>;
144
+ };
145
+ }
146
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}