@mcpg-dev/pulumi 0.1.0-beta.11

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/BUILD.bazel ADDED
@@ -0,0 +1,24 @@
1
+ load("@aspect_rules_js//js:defs.bzl", "js_library")
2
+ load("@npm//:defs.bzl", "npm_link_all_packages")
3
+
4
+ # This package's npm dependencies, linked the way node resolves them.
5
+ npm_link_all_packages(name = "node_modules")
6
+
7
+ # Every workspace package needs a `pkg` target: npm_link_all_packages resolves
8
+ # a `workspace:*` dependency to one, and the root link covers the whole
9
+ # workspace — so a package without it breaks the graph for everyone, not just
10
+ # for itself.
11
+ js_library(
12
+ name = "pkg",
13
+ srcs = glob(
14
+ ["**/*"],
15
+ allow_empty = True,
16
+ exclude = [
17
+ "node_modules/**",
18
+ "dist/**",
19
+ ".next/**",
20
+ "BUILD.bazel",
21
+ ],
22
+ ),
23
+ visibility = ["//visibility:public"],
24
+ )
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # @mcpg/pulumi
2
+
3
+ Opinionated Pulumi components for running MCPG on Kubernetes: the operator, the
4
+ CRDs, cluster trust, gateways, plugin sets, routes, and tenants. Each component
5
+ wraps a piece of the platform that is easy to get subtly wrong — CRD lifecycle,
6
+ gateway configuration shape, tenant isolation — behind typed TypeScript inputs.
7
+ Built on `@mcpg/pulumi-crds` (the generated, typed CRD SDK) and
8
+ `@pulumi/kubernetes`.
9
+
10
+ Reach for it when your MCPG deployment lives in a Pulumi program and you would
11
+ rather express "one operator, one gateway, three tenants" than assemble Helm
12
+ releases and raw custom resources by hand.
13
+
14
+ ## Prerequisites
15
+
16
+ - Pulumi with the TypeScript runtime, and a Kubernetes provider configured for
17
+ the target cluster.
18
+ - cert-manager in the cluster, unless you turn it off. The operator's admission
19
+ webhook fails closed and needs real TLS, so `Operator` sets
20
+ `certManager.enabled=true` by default.
21
+
22
+ ## Quick start
23
+
24
+ ```ts
25
+ import { McpgStack } from "@mcpg/pulumi";
26
+
27
+ new McpgStack("prod", {
28
+ operator: { chartVersion: "<chart-version>" },
29
+ gateway: {
30
+ image: { repository: "ghcr.io/mcpg-dev/source-code/gateway", tag: "<tag>" },
31
+ governance: { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } },
32
+ },
33
+ });
34
+ ```
35
+
36
+ `McpgStack` composes the common case: an `Operator`, a `TrustBootstrap` seeding
37
+ the cluster-default revocation list (set `trust: false` to skip it), and — when
38
+ `gateway` is given — one `Gateway` in the operator's namespace. Both of the
39
+ latter depend on the operator being installed first.
40
+
41
+ The package is built from this workspace:
42
+
43
+ ```bash
44
+ pnpm --filter ./iac/pulumi/components run build # tsc → bin/
45
+ pnpm --filter ./iac/pulumi/components exec tsc -b --noEmit # tsc --noEmit
46
+ ```
47
+
48
+ ## Components
49
+
50
+ | Component | Creates |
51
+ |---|---|
52
+ | `Operator` | The operator Helm release plus the CRDs as first-class resources. |
53
+ | `Gateway` | An `MCPGGateway`, with `spec.config` assembled by the config builder. |
54
+ | `PluginSet` | An `MCPGPluginSet` — plugin entries and optional capability grants. |
55
+ | `TrustBootstrap` | The cluster-default `MCPGRevocationList`, and carries the signing-key reference. |
56
+ | `Cluster` | An `MCPGCluster` — the coordination backend a gateway's `clusterRef` points at. |
57
+ | `Route` | An `MCPGRoute` — a tool subset bound into a shared gateway with identity, policy, and audit chains. |
58
+ | `TenantCR` | An `MCPGTenant` — declarative tenant governance. |
59
+ | `Tenant` | A namespace with isolation, and optionally a plugin set and a gateway. |
60
+ | `McpgStack` | Operator plus trust plus one gateway. |
61
+
62
+ ### Operator and CRD lifecycle
63
+
64
+ Helm installs the files under a chart's `crds/` directory once and never
65
+ upgrades or deletes them. `Operator` sidesteps that by applying the CRDs as a
66
+ `ConfigGroup` it owns — server-side applied, upgraded like any other resource —
67
+ and telling the chart to stand back with `skipCrds` plus `crd.install=false`.
68
+ `crdsDir` points at the CRD YAMLs (default `../../codegen/schemas/v1alpha1/crds`,
69
+ resolved from the Pulumi program's directory).
70
+
71
+ The release defaults to namespace `mcpg-system`, chart `mcpg-operator` from
72
+ `ociChartRepo()`, and cert-manager enabled. Set `watchNamespace` to restrict the
73
+ operator to a single namespace. Anything in `values` is spread over those
74
+ defaults, so a key you supply replaces the corresponding default block.
75
+
76
+ `ociChartRepo()` composes `oci://<base>/charts` from the registry coordinates in
77
+ `src/oci.ts`, whose defaults mirror `tools/release/oci-registry.json`. Override
78
+ one chart with `chartRepo`, or a whole stack with `MCPG_OCI_HOST` /
79
+ `MCPG_OCI_NAMESPACE` / `MCPG_OCI_PATH` — the same environment contract the shell
80
+ and Node publish helpers honour. `ociImageRepo(name)` and `ociPluginRegistry()`
81
+ compose image and plugin references off the same base.
82
+
83
+ ### Gateway readiness
84
+
85
+ `Gateway` annotates the resource with `pulumi.com/waitFor: condition=Ready`, so
86
+ `pulumi up` waits on the operator reporting the gateway ready rather than on the
87
+ custom resource merely existing. Pass `waitForReady: false` to skip the wait.
88
+
89
+ ### Tenancy: two different things
90
+
91
+ `Tenant` is an imperative fan-out — it creates the namespace, a default-deny
92
+ cross-tenant ingress `NetworkPolicy` (unless `networkPolicy: false`), and
93
+ optionally a plugin set and a gateway inside it. Instantiate it in a loop to
94
+ build a fleet. It does **not** create an `MCPGTenant`, so it does not engage the
95
+ operator's tenant governance.
96
+
97
+ `TenantCR` creates the `MCPGTenant` custom resource: the plugin allowlist,
98
+ per-namespace quotas, replica ceilings, and exclusive namespace ownership the
99
+ operator enforces at admission. Use it when tenant boundaries must be enforced
100
+ rather than merely arranged, alongside or instead of `Tenant`.
101
+
102
+ ### Cluster credentials
103
+
104
+ `Cluster` accepts `credentialRefs` naming pre-existing Secrets, and
105
+ `credentials`, where an entry carrying `data` makes the component create the
106
+ Secret in `operatorNamespace` (default `mcpg-system`) and wire the reference for
107
+ you. Both forms surface to the gateway as `cred://cluster/<name>`.
108
+ `TrustBootstrap` takes a signing-key Secret reference the same way: only the
109
+ reference travels, never the key bytes, so no signing material lands in Pulumi
110
+ state.
111
+
112
+ ## Configuration
113
+
114
+ `Gateway` builds the gateway's `spec.config` from typed sections. The operator
115
+ passes that document through untouched, and the gateway parses it strictly —
116
+ unknown keys are a boot-time error, which makes the shape worth getting right.
117
+
118
+ ```ts
119
+ import { Gateway } from "@mcpg/pulumi";
120
+
121
+ new Gateway("orders", {
122
+ namespace: "mcpg-system",
123
+ image: { repository: "ghcr.io/mcpg-dev/source-code/gateway", tag: "<tag>" },
124
+ server: { bind_address: "0.0.0.0:8080" },
125
+ governance: { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } },
126
+ plugins: [
127
+ { id: "dev.mcpg.backend.sql", source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-sql:protocol-1" } },
128
+ ],
129
+ extraConfig: { mcp: { capabilities: { tools: [] } } },
130
+ });
131
+ ```
132
+
133
+ | Field | Type | Default | Description |
134
+ |---|---|---|---|
135
+ | `server` | object | omitted | Emitted at `config.gateway.server`, under the `gateway:` umbrella — a top-level `server` key is rejected by the gateway's parser. |
136
+ | `governance` | object | omitted | Emitted at `config.governance`. Audit sinks are a list (`audit.sinks[]`), not a scalar. |
137
+ | `observability` | object | omitted | Emitted at `config.observability`. |
138
+ | `mcp` | object | omitted | Emitted at `config.mcp`. |
139
+ | `plugins` | array | omitted | Emitted at `config.plugins`, and only when non-empty. Each entry carries `id` and a `source` declaring exactly one of `path` or `oci`; the per-entry toggle is `disabled`, not `enabled`. |
140
+ | `extraConfig` | object | `{}` | An arbitrary configuration fragment merged last, so its top-level keys win. The escape hatch for anything the typed sections do not cover. |
141
+
142
+ The same last-wins rule applies one level up: `extraSpec` on `Gateway` is merged
143
+ over the assembled `spec`, after the typed passthrough blocks
144
+ (`acceptedRouteNamespaces`, `podAnnotations`, `podLabels`, `resources`,
145
+ `service`, `ingress`, `autoscaling`, `monitoring`, `networkPolicy`,
146
+ `podDisruptionBudget`, `workloadIdentity`, `scheduling`, `probes`,
147
+ `imagePullSecrets`).
148
+
149
+ The config builder's semantics are covered by unit tests that need no
150
+ dependencies beyond Node itself:
151
+
152
+ ```bash
153
+ pnpm --filter ./iac/pulumi/components run build
154
+ node --test iac/pulumi/components/bin/config.test.js
155
+ ```
156
+
157
+ ## Licence
158
+
159
+ Apache-2.0.
160
+
161
+ ## See also
162
+
163
+ - <https://mcpg.dev/docs/self-hosting/pulumi> — deploying MCPG with Pulumi.
164
+ - <https://mcpg.dev/docs/reference/operator-crds> — the custom resources these
165
+ components create.
166
+ - <https://mcpg.dev/docs/reference/configuration> — the full gateway
167
+ configuration schema behind `spec.config`.
168
+ - `iac/pulumi/crds` (the typed CRD SDK) and `iac/pulumi/policy` (the CrossGuard
169
+ policy pack that validates these resources at preview time).
@@ -0,0 +1,44 @@
1
+ import * as pulumi from "@pulumi/pulumi";
2
+ import { mcpg } from "@mcpg-dev/pulumi-crds";
3
+ export interface ClusterCredential {
4
+ /** cred://cluster/<name>. */
5
+ name: string;
6
+ secretName: string;
7
+ key?: string;
8
+ /** When set, the component CREATES the Secret in operatorNamespace; else it is assumed to pre-exist. */
9
+ data?: {
10
+ [key: string]: string;
11
+ };
12
+ }
13
+ export interface ClusterArgs {
14
+ /** single_node (default) | redis | nats | consul | etcd. */
15
+ backend?: string;
16
+ /** Per-backend connection config. MUST be empty for single_node, non-empty otherwise. */
17
+ config?: {
18
+ [key: string]: any;
19
+ };
20
+ /** Optional { name } of the cluster-scoped MCPGPlugin supplying the cdylib. */
21
+ pluginRef?: {
22
+ name: string;
23
+ };
24
+ /** Optional [{ name, secretName, key? }] referencing PRE-EXISTING Secrets, surfaced as cred://cluster/<name>. */
25
+ credentialRefs?: any[];
26
+ /** Backend credentials this component manages — creates the Secret (when `data` is set) in operatorNamespace + wires the ref. */
27
+ credentials?: ClusterCredential[];
28
+ /** Namespace the operator runs in — where credential Secrets must live. */
29
+ operatorNamespace?: pulumi.Input<string>;
30
+ labels?: {
31
+ [key: string]: string;
32
+ };
33
+ resourceName?: string;
34
+ }
35
+ /**
36
+ * An MCPGCluster (cluster-scoped): the coordination backend a gateway's
37
+ * `clusterRef` points at. `single_node` takes no config; external backends
38
+ * require a non-empty connection block.
39
+ */
40
+ export declare class Cluster extends pulumi.ComponentResource {
41
+ readonly cluster: mcpg.v1alpha1.MCPGCluster;
42
+ readonly name: pulumi.Output<string>;
43
+ constructor(name: string, args?: ClusterArgs, opts?: pulumi.ComponentResourceOptions);
44
+ }
package/bin/cluster.js ADDED
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Cluster = void 0;
37
+ const pulumi = __importStar(require("@pulumi/pulumi"));
38
+ const k8s = __importStar(require("@pulumi/kubernetes"));
39
+ const pulumi_crds_1 = require("@mcpg-dev/pulumi-crds");
40
+ /**
41
+ * An MCPGCluster (cluster-scoped): the coordination backend a gateway's
42
+ * `clusterRef` points at. `single_node` takes no config; external backends
43
+ * require a non-empty connection block.
44
+ */
45
+ class Cluster extends pulumi.ComponentResource {
46
+ constructor(name, args = {}, opts) {
47
+ super("mcpg:index:Cluster", name, {}, opts);
48
+ const cName = args.resourceName ?? name;
49
+ const ns = args.operatorNamespace ?? "mcpg-system";
50
+ // Managed credential Secrets (operator namespace) + their refs.
51
+ const managedRefs = [];
52
+ const secretDeps = [];
53
+ for (const c of args.credentials ?? []) {
54
+ if (c.data) {
55
+ const sec = new k8s.core.v1.Secret(`${cName}-cred-${c.name}`, {
56
+ metadata: { name: c.secretName, namespace: ns },
57
+ stringData: c.data,
58
+ type: "Opaque",
59
+ }, { parent: this });
60
+ secretDeps.push(sec);
61
+ }
62
+ managedRefs.push(c.key ? { name: c.name, secretName: c.secretName, key: c.key } : { name: c.name, secretName: c.secretName });
63
+ }
64
+ const credentialRefs = [...(args.credentialRefs ?? []), ...managedRefs];
65
+ const spec = { backend: args.backend ?? "single_node" };
66
+ if (args.config && Object.keys(args.config).length > 0)
67
+ spec.config = args.config;
68
+ if (args.pluginRef)
69
+ spec.pluginRef = args.pluginRef;
70
+ if (credentialRefs.length > 0)
71
+ spec.credentialRefs = credentialRefs;
72
+ this.cluster = new pulumi_crds_1.mcpg.v1alpha1.MCPGCluster(cName, {
73
+ metadata: { name: cName, labels: args.labels },
74
+ spec: spec,
75
+ }, { parent: this, dependsOn: secretDeps });
76
+ this.name = pulumi.output(cName);
77
+ this.registerOutputs({ name: this.name });
78
+ }
79
+ }
80
+ exports.Cluster = Cluster;
@@ -0,0 +1,30 @@
1
+ export interface GatewayConfigInput {
2
+ /**
3
+ * Gateway server/listener config. Emitted at config.gateway.server (the
4
+ * `gateway:` AppConfig umbrella holds server/admin/control_plane), NOT a
5
+ * top-level `server` key — that trips AppConfig's deny_unknown_fields.
6
+ */
7
+ server?: any;
8
+ /**
9
+ * config.governance section (access / policy / approvals / audit). Audit
10
+ * sinks are a LIST, not a scalar:
11
+ * { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } }.
12
+ * `dev.mcpg.builtin.audit.local-file` is the canonical built-in audit sink.
13
+ */
14
+ governance?: any;
15
+ /** config.observability section. */
16
+ observability?: any;
17
+ /** config.mcp section (capabilities, etc.). */
18
+ mcp?: any;
19
+ /**
20
+ * Ordered config.plugins list (AppConfig PluginEntryConfig). Each entry:
21
+ * { id, source: { path | oci }, class?, kind?, config?, enforce?, disabled? }.
22
+ * The toggle is `disabled` (bool, default false) — there is no `enabled`.
23
+ * A `source` declaring exactly one of path/oci is required.
24
+ */
25
+ plugins?: any[];
26
+ /** Arbitrary AppConfig fragment merged LAST into spec.config (wins). */
27
+ extraConfig?: Record<string, any>;
28
+ }
29
+ /** Assemble spec.config from typed sections + extraConfig (extraConfig wins). */
30
+ export declare function buildConfig(input: GatewayConfigInput): Record<string, any>;
package/bin/config.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ // The gateway config builder: assemble spec.config (the preserve-unknown
3
+ // AppConfig) from typed convenience sections plus an `extraConfig` escape hatch
4
+ // deep-merged LAST so it wins. Mirrors the Terraform module's config builder.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildConfig = buildConfig;
7
+ /** Assemble spec.config from typed sections + extraConfig (extraConfig wins). */
8
+ function buildConfig(input) {
9
+ const cfg = {};
10
+ // `server` lives under the `gateway:` umbrella, not at the top level.
11
+ if (input.server)
12
+ cfg.gateway = { server: input.server };
13
+ if (input.governance)
14
+ cfg.governance = input.governance;
15
+ if (input.observability)
16
+ cfg.observability = input.observability;
17
+ if (input.mcp)
18
+ cfg.mcp = input.mcp;
19
+ if (input.plugins && input.plugins.length > 0)
20
+ cfg.plugins = input.plugins;
21
+ return { ...cfg, ...(input.extraConfig ?? {}) };
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // Unit tests for the config builder. Uses node's built-in test runner +
7
+ // assert (no extra deps). Run: `tsc && node --test bin/config.test.js`.
8
+ const node_test_1 = require("node:test");
9
+ const strict_1 = __importDefault(require("node:assert/strict"));
10
+ const config_1 = require("./config");
11
+ (0, node_test_1.test)("typed sections are included; absent ones omitted", () => {
12
+ const c = (0, config_1.buildConfig)({ governance: { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } } });
13
+ strict_1.default.equal(c.governance.audit.sinks[0].kind, "dev.mcpg.builtin.audit.local-file");
14
+ strict_1.default.equal("gateway" in c, false);
15
+ strict_1.default.equal("observability" in c, false);
16
+ });
17
+ (0, node_test_1.test)("server nests under config.gateway.server (not a top-level server key)", () => {
18
+ const c = (0, config_1.buildConfig)({ server: { listen_addr: "0.0.0.0:8080" } });
19
+ strict_1.default.equal("server" in c, false);
20
+ strict_1.default.deepEqual(c.gateway.server, { listen_addr: "0.0.0.0:8080" });
21
+ });
22
+ (0, node_test_1.test)("plugins included only when non-empty", () => {
23
+ strict_1.default.equal("plugins" in (0, config_1.buildConfig)({ plugins: [] }), false);
24
+ strict_1.default.deepEqual((0, config_1.buildConfig)({ plugins: [{ id: "db.read" }] }).plugins, [{ id: "db.read" }]);
25
+ });
26
+ (0, node_test_1.test)("extraConfig is merged LAST and wins", () => {
27
+ const c = (0, config_1.buildConfig)({
28
+ governance: { a: 1 },
29
+ extraConfig: { governance: { b: 2 }, extra: true },
30
+ });
31
+ strict_1.default.deepEqual(c.governance, { b: 2 }); // extraConfig wins
32
+ strict_1.default.equal(c.extra, true);
33
+ });
34
+ (0, node_test_1.test)("empty input yields empty config", () => {
35
+ strict_1.default.deepEqual((0, config_1.buildConfig)({}), {});
36
+ });
@@ -0,0 +1,52 @@
1
+ import * as pulumi from "@pulumi/pulumi";
2
+ import { mcpg } from "@mcpg-dev/pulumi-crds";
3
+ import { GatewayConfigInput } from "./config";
4
+ export interface GatewayArgs extends GatewayConfigInput {
5
+ namespace: pulumi.Input<string>;
6
+ /** Gateway image (CRD spec.image — e.g. { repository, tag }). Required. */
7
+ image: any;
8
+ replicas?: number;
9
+ pluginSetRef?: pulumi.Input<string>;
10
+ revocationListRef?: pulumi.Input<string>;
11
+ /** MCPGCluster coordination backend (spec.clusterRef.name) for HA gateways. */
12
+ clusterRef?: pulumi.Input<string>;
13
+ /** Soft-tenancy: namespaces whose MCPGRoutes this gateway accepts. */
14
+ acceptedRouteNamespaces?: string[];
15
+ podAnnotations?: {
16
+ [key: string]: string;
17
+ };
18
+ podLabels?: {
19
+ [key: string]: string;
20
+ };
21
+ resources?: any;
22
+ service?: any;
23
+ ingress?: any;
24
+ autoscaling?: any;
25
+ monitoring?: any;
26
+ networkPolicy?: any;
27
+ podDisruptionBudget?: any;
28
+ workloadIdentity?: any;
29
+ scheduling?: any;
30
+ probes?: any;
31
+ imagePullSecrets?: any;
32
+ /** Arbitrary spec-level fields merged LAST (for spec keys not yet typed). */
33
+ extraSpec?: {
34
+ [key: string]: any;
35
+ };
36
+ labels?: {
37
+ [key: string]: string;
38
+ };
39
+ /** Default true → annotate `pulumi.com/waitFor: condition=Ready`. */
40
+ waitForReady?: boolean;
41
+ /** MCPGGateway metadata.name (defaults to the component name). */
42
+ resourceName?: string;
43
+ }
44
+ /**
45
+ * An MCPGGateway built from typed inputs + the config builder. Readiness is the
46
+ * provider's built-in await via the `pulumi.com/waitFor` annotation.
47
+ */
48
+ export declare class Gateway extends pulumi.ComponentResource {
49
+ readonly gateway: mcpg.v1alpha1.MCPGGateway;
50
+ readonly name: pulumi.Output<string>;
51
+ constructor(name: string, args: GatewayArgs, opts?: pulumi.ComponentResourceOptions);
52
+ }
package/bin/gateway.js ADDED
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Gateway = void 0;
37
+ const pulumi = __importStar(require("@pulumi/pulumi"));
38
+ const pulumi_crds_1 = require("@mcpg-dev/pulumi-crds");
39
+ const config_1 = require("./config");
40
+ /**
41
+ * An MCPGGateway built from typed inputs + the config builder. Readiness is the
42
+ * provider's built-in await via the `pulumi.com/waitFor` annotation.
43
+ */
44
+ class Gateway extends pulumi.ComponentResource {
45
+ constructor(name, args, opts) {
46
+ super("mcpg:index:Gateway", name, {}, opts);
47
+ const gwName = args.resourceName ?? name;
48
+ const spec = {
49
+ image: args.image,
50
+ config: (0, config_1.buildConfig)(args),
51
+ };
52
+ if (args.replicas !== undefined)
53
+ spec.replicas = args.replicas;
54
+ if (args.pluginSetRef)
55
+ spec.pluginSetRef = { name: args.pluginSetRef };
56
+ if (args.revocationListRef)
57
+ spec.revocationListRef = { name: args.revocationListRef };
58
+ if (args.clusterRef)
59
+ spec.clusterRef = { name: args.clusterRef };
60
+ // Typed passthrough blocks (same spec surface as the TF gateway module).
61
+ const optional = {
62
+ acceptedRouteNamespaces: args.acceptedRouteNamespaces,
63
+ podAnnotations: args.podAnnotations,
64
+ podLabels: args.podLabels,
65
+ resources: args.resources,
66
+ service: args.service,
67
+ ingress: args.ingress,
68
+ autoscaling: args.autoscaling,
69
+ monitoring: args.monitoring,
70
+ networkPolicy: args.networkPolicy,
71
+ podDisruptionBudget: args.podDisruptionBudget,
72
+ workloadIdentity: args.workloadIdentity,
73
+ scheduling: args.scheduling,
74
+ probes: args.probes,
75
+ imagePullSecrets: args.imagePullSecrets,
76
+ };
77
+ for (const [k, v] of Object.entries(optional))
78
+ if (v !== undefined)
79
+ spec[k] = v;
80
+ Object.assign(spec, args.extraSpec ?? {}); // escape hatch wins (matches TF extra_spec)
81
+ const annotations = args.waitForReady === false ? {} : { "pulumi.com/waitFor": "condition=Ready" };
82
+ this.gateway = new pulumi_crds_1.mcpg.v1alpha1.MCPGGateway(gwName, {
83
+ metadata: { name: gwName, namespace: args.namespace, labels: args.labels, annotations },
84
+ spec: spec,
85
+ }, { parent: this });
86
+ this.name = pulumi.output(gwName);
87
+ this.registerOutputs({ name: this.name });
88
+ }
89
+ }
90
+ exports.Gateway = Gateway;
package/bin/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export * from "./config";
2
+ export * from "./oci";
3
+ export * from "./operator";
4
+ export * from "./gateway";
5
+ export * from "./pluginSet";
6
+ export * from "./trustBootstrap";
7
+ export * from "./tenant";
8
+ export * from "./cluster";
9
+ export * from "./route";
10
+ export * from "./tenantCr";
11
+ export * from "./mcpgStack";
package/bin/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./config"), exports);
18
+ __exportStar(require("./oci"), exports);
19
+ __exportStar(require("./operator"), exports);
20
+ __exportStar(require("./gateway"), exports);
21
+ __exportStar(require("./pluginSet"), exports);
22
+ __exportStar(require("./trustBootstrap"), exports);
23
+ __exportStar(require("./tenant"), exports);
24
+ __exportStar(require("./cluster"), exports);
25
+ __exportStar(require("./route"), exports);
26
+ __exportStar(require("./tenantCr"), exports);
27
+ __exportStar(require("./mcpgStack"), exports);
@@ -0,0 +1,18 @@
1
+ import * as pulumi from "@pulumi/pulumi";
2
+ import { Operator, OperatorArgs } from "./operator";
3
+ import { Gateway, GatewayArgs } from "./gateway";
4
+ export interface McpgStackArgs {
5
+ operator: OperatorArgs;
6
+ /** Optional single gateway for the common case. */
7
+ gateway?: Omit<GatewayArgs, "namespace"> & {
8
+ namespace?: pulumi.Input<string>;
9
+ };
10
+ /** Seed the cluster-default revocation list (default true). */
11
+ trust?: boolean;
12
+ }
13
+ /** Convenience composition: operator + cluster trust + one gateway. */
14
+ export declare class McpgStack extends pulumi.ComponentResource {
15
+ readonly operator: Operator;
16
+ readonly gateway?: Gateway;
17
+ constructor(name: string, args: McpgStackArgs, opts?: pulumi.ComponentResourceOptions);
18
+ }