@cyc-seattle/platform 1.1.0 → 1.2.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/README.md CHANGED
@@ -6,19 +6,19 @@ app owns. The apps that run on it live in their own repos, such as
6
6
 
7
7
  ## Stacks
8
8
 
9
- | Stack | Holds | Applied by |
10
- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
11
- | [`bootstrap`](stacks/bootstrap) | Service accounts and project IAM, the Pulumi state buckets and KMS keys, and the org's GitHub repos and settings | A human with project Owner and `gh` `admin:org`. Never CI. |
12
- | [`cloud`](stacks/cloud) | The VPC, the cluster subnet and its Cloud NAT on a static address, the private services peering, the prod and dev Cloud SQL instances, the DNS zones, and Artifact Registry | `deploy-runner`, from Actions after approval. A deployer, with `mise run deploy`, when breaking glass. |
13
- | [`cluster`](stacks/cluster) | The GKE Autopilot cluster, the shared Gateway, its address, certificates, and dev's DNS records, the `dev` and `prod` namespaces with their quotas and network policies, dev's RBAC, the prod Job alerts, and each environment's `platform/outputs.json` | `deploy-runner`, from Actions after approval. A deployer, with `mise run deploy`, when breaking glass. |
14
- | [`smoke`](stacks/smoke) | One `WebService` in dev, at `smoke.dev.cycsail.team`, for the integration tests | `deploy-dev`, from Actions on every PR. A deployer, with `PULUMI_STACK=dev mise run deploy`, when breaking glass. |
9
+ | Stack | Holds | Applied by |
10
+ | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
11
+ | [`bootstrap`](stacks/bootstrap) | Service accounts and project IAM, the Pulumi state buckets and KMS keys, and the org's GitHub repos and settings | A human with project Owner and `gh` `admin:org`. Never CI. |
12
+ | [`infra`](stacks/infra) | The VPC, the cluster subnet and its Cloud NAT on a static address, the private services peering, the prod and dev Cloud SQL instances, the DNS zones, Artifact Registry, the GKE Autopilot cluster, the shared Gateway, its address, certificates, and dev's DNS records, the `dev` and `prod` namespaces with their quotas and network policies, dev's RBAC, the prod Job alerts, and each environment's `platform/outputs.json` | `deploy-runner`, from Actions after approval. A deployer, with `mise run deploy`, when breaking glass. |
13
+ | [`smoke`](stacks/smoke) | One `WebService` in dev, at `smoke.dev.cycsail.team`, for the integration tests | `deploy-dev`, from Actions on every PR. A deployer, with `PULUMI_STACK=dev mise run deploy`, when breaking glass. |
14
+ | [`backend`](stacks/backend) | Directus, with the schema apply from `schemas/`, its roles, policies, and permission rules, the sync machine users, its OIDC client, and MCP | `deploy-dev`, from Actions on every PR. Dev only, until prod cuts over (cyc-seattle/workplace#6 step 6). |
15
15
 
16
16
  ## @cyc-seattle/platform
17
17
 
18
18
  `src/` is the `@cyc-seattle/platform` package, which the stacks here and the apps' stacks import:
19
19
 
20
20
  - `getPlatformOutputs()` reads an environment's `platform/outputs.json` from its state bucket. The
21
- `cluster` stack writes it. It holds the environment's namespace and domain, the Gateway and its
21
+ `infra` stack writes it. It holds the environment's namespace and domain, the Gateway and its
22
22
  address (`gatewayAddress`, for an app's own DNS records), and the Cloud SQL instance's connection
23
23
  name and private IP (`sqlHost`). Dev stacks can't read prod's backend, so this replaces a
24
24
  StackReference for platform values (cyc-seattle/isthmia#215).
@@ -56,19 +56,19 @@ two syncs as CronJobs) run in both, and dev adds Mailpit and the Clubspot and Wo
56
56
 
57
57
  Each namespace denies ingress from other namespaces except the load balancer's. Dev also admits the
58
58
  Kubernetes API's service proxy, which the integration tests use, and denies egress to the mail ports
59
- (25, 465, 587) outside the cluster. `cluster` writes dev's A records; each prod app writes its own,
59
+ (25, 465, 587) outside the cluster. `infra` writes dev's A records; each prod app writes its own,
60
60
  pointing at `gatewayAddress`.
61
61
 
62
62
  `deploy-dev` reads Secret Manager secrets whose IDs start with `dev-`. Read them with
63
63
  `gcp.secretmanager.getSecretVersionAccess`, which needs only the accessor role.
64
64
 
65
- `cloud` creates each app's dev database, user, and password secret (`dev-db-<name>-password`) on
66
- `cyc-dev`, for each name in `cloud:devDatabases`. To add an app's dev database, add its name there in a
65
+ `infra` creates each app's dev database, user, and password secret (`dev-db-<name>-password`) on
66
+ `cyc-dev`, for each name in `infra:devDatabases`. To add an app's dev database, add its name there in a
67
67
  platform PR: Cloud SQL ignores IAM conditions on its user and database calls, so `deploy-dev` can't
68
68
  hold a role scoped to `cyc-dev`.
69
69
 
70
70
  A Job that fails in `prod`, or a CronJob there with no successful Job in 3 hours, raises an alert.
71
- It emails each address in `cluster:alertEmails`, a secret in the stack's config, which holds the
71
+ It emails each address in `infra:alertEmails`, a secret in the stack's config, which holds the
72
72
  maintainer's address (#20).
73
73
 
74
74
  ## Setup
@@ -100,11 +100,11 @@ GitHub environment that holds its identity and state bucket:
100
100
 
101
101
  `prod-preview` runs `mise run preview` as `deploy-runner` and writes the diff to the job summary.
102
102
  `prod` runs `mise run deploy` on the same commit once approved. It runs only when the preview shows
103
- changes in `cloud` or `cluster`, so a merge that changes nothing in prod asks for no approval. A PR from a fork gets no OIDC token,
103
+ changes in `infra`, so a merge that changes nothing in prod asks for no approval. A PR from a fork gets no OIDC token,
104
104
  so its `dev` job is skipped.
105
105
 
106
- `PULUMI_STACK` picks what the tasks run (`scripts/each-stack`): `dev` is `smoke`, and `prod` is
107
- `cloud`, then `cluster`. `integration` is dev only.
106
+ `PULUMI_STACK` picks what the tasks run (`scripts/each-stack`): `dev` is `smoke`, then `backend`, and
107
+ `prod` is `infra`. `integration` is dev only.
108
108
 
109
109
  `bootstrap` is never deployed from Actions (cyc-seattle/isthmia#118). It holds the identities that
110
110
  CI assumes, and a human with project Owner and `gh` `admin:org` applies it with the tasks below.
@@ -121,8 +121,8 @@ mise run deploy
121
121
  PULUMI_STACK=dev mise run deploy
122
122
  ```
123
123
 
124
- `mise run deploy` applies `cloud`, then `cluster`. Prod stacks read `cloud`'s outputs through a
125
- StackReference. Dev stacks can't read prod state, so `cluster` writes each environment's platform
124
+ `mise run deploy` applies `infra`. isthmia's prod stacks read its outputs through a StackReference.
125
+ Dev stacks can't read prod state, so `infra` writes each environment's platform
126
126
  values to `platform/outputs.json` in that environment's state bucket.
127
127
 
128
128
  `bootstrap`'s GitHub provider uses `gh auth token`, so log `gh` in as a cyc-seattle org owner with
@@ -11,7 +11,7 @@ export interface ClusterProviderArgs {
11
11
  /**
12
12
  * A Kubernetes provider for the environment's cluster. Its kubeconfig runs gke-gcloud-auth-plugin
13
13
  * with Application Default Credentials, so it is the same on every run, unlike one that embeds an
14
- * access token. The plugin must be on PATH: `mise run install` adds it. The cluster stack passes
14
+ * access token. The plugin must be on PATH: `mise run install` adds it. The infra stack passes
15
15
  * only the endpoint, because it writes the rest.
16
16
  */
17
17
  export declare function clusterProvider(platform: pulumi.Input<{
@@ -3,7 +3,7 @@ import * as pulumi from "@pulumi/pulumi";
3
3
  /**
4
4
  * A Kubernetes provider for the environment's cluster. Its kubeconfig runs gke-gcloud-auth-plugin
5
5
  * with Application Default Credentials, so it is the same on every run, unlike one that embeds an
6
- * access token. The plugin must be on PATH: `mise run install` adds it. The cluster stack passes
6
+ * access token. The plugin must be on PATH: `mise run install` adds it. The infra stack passes
7
7
  * only the endpoint, because it writes the rest.
8
8
  */
9
9
  export function clusterProvider(platform, name = "cluster", opts, args = {}) {
package/dist/outputs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as gcp from "@pulumi/gcp";
2
2
  import * as pulumi from "@pulumi/pulumi";
3
3
  import { z } from "zod";
4
- // The cluster stack writes this object to each environment's state bucket, because a StackReference
4
+ // The infra stack writes this object to each environment's state bucket, because a StackReference
5
5
  // can't cross from a dev stack into prod's backend (cyc-seattle/isthmia#215).
6
6
  export const platformOutputsSchema = z.object({
7
7
  project: z.string().min(1),
@@ -49,10 +49,10 @@ export async function readPlatformOutputs(args = {}) {
49
49
  ({ content } = await gcp.storage.getBucketObjectContent({ bucket, name: outputsObject }));
50
50
  }
51
51
  catch (e) {
52
- throw new Error(`Can't read ${source}. The cluster stack writes it.\n${e.message}`);
52
+ throw new Error(`Can't read ${source}. The infra stack writes it.\n${e.message}`);
53
53
  }
54
54
  if (!content) {
55
- throw new Error(`${source} is empty. The cluster stack writes it.`);
55
+ throw new Error(`${source} is empty. The infra stack writes it.`);
56
56
  }
57
57
  return parsePlatformOutputs(content, source);
58
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyc-seattle/platform",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Pulumi components for CYC's shared Google Cloud platform: WebService, the platform outputs reader, and the stacks that build the platform",
5
5
  "author": "CYC Community Sailing Center",
6
6
  "license": "Apache-2.0",
@@ -47,6 +47,7 @@
47
47
  "@amiceli/vitest-cucumber": "7.0.0",
48
48
  "@cyc-seattle/ts-config": "^0.1.2",
49
49
  "@pulumi/command": "1.2.1",
50
+ "@pulumi/docker-build": "0.0.22",
50
51
  "@pulumi/gcp": "10.2.0",
51
52
  "@pulumi/github": "6.15.0",
52
53
  "@pulumi/kubernetes": "4.34.2",