@vaharoni/devops 1.2.18 → 1.3.1

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.
Files changed (41) hide show
  1. package/dist/{chunk-RZ46YYZZ.js → chunk-6FEVIEFY.js} +2 -1
  2. package/dist/{chunk-WKP7EQNU.js → chunk-QOZ6NZJC.js} +1 -1
  3. package/dist/{chunk-N7EX3HJH.js → chunk-UZAJJUGJ.js} +1 -1
  4. package/dist/devops.js +32 -33
  5. package/dist/index.d.ts +6 -3
  6. package/dist/index.js +2 -2
  7. package/dist/plugins.js +2 -2
  8. package/dist/src/target-templates/infra-variants/digitalocean/.devops/config/constants.yaml +2 -2
  9. package/dist/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml +13 -13
  10. package/dist/src/target-templates/infra-variants/gcloud/.devops/config/constants.yaml +2 -2
  11. package/dist/src/target-templates/infra-variants/gcloud/.github/workflows/k8s-build.yaml +15 -15
  12. package/dist/src/target-templates/infra-variants/hetzner/.devops/config/constants.yaml +6 -2
  13. package/dist/src/target-templates/infra-variants/hetzner/.github/workflows/k8s-build.yaml +13 -13
  14. package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-oidc@v1/action.yaml +29 -0
  15. package/{src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry@v1 → dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-sa@v1}/action.yaml +2 -2
  16. package/package.json +1 -1
  17. package/src/cli/core/constant.ts +1 -1
  18. package/src/cli/core/init.ts +16 -15
  19. package/src/cli/core/namespace.ts +5 -5
  20. package/src/cli/core/registry.ts +1 -1
  21. package/src/libs/digital-ocean/container-reg.ts +2 -2
  22. package/src/libs/{hetzner/reg-secret.ts → registry/image-pull-secret.ts} +9 -9
  23. package/src/target-templates/infra-variants/digitalocean/.devops/config/constants.yaml +2 -2
  24. package/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml +13 -13
  25. package/src/target-templates/infra-variants/gcloud/.devops/config/constants.yaml +2 -2
  26. package/src/target-templates/infra-variants/gcloud/.github/workflows/k8s-build.yaml +15 -15
  27. package/src/target-templates/infra-variants/hetzner/.devops/config/constants.yaml +6 -2
  28. package/src/target-templates/infra-variants/hetzner/.github/workflows/k8s-build.yaml +13 -13
  29. package/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-oidc@v1/action.yaml +29 -0
  30. package/{dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry@v1 → src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-sa@v1}/action.yaml +2 -2
  31. package/src/types/index.ts +2 -1
  32. /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{build-image@v1 → common/build-image@v1}/action.yaml +0 -0
  33. /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{db-migrate@v1 → common/db-migrate@v1}/action.yaml +0 -0
  34. /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-cloudrun@v1 → common/deploy-image-cloudrun@v1}/action.yaml +0 -0
  35. /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-k8s@v1 → common/deploy-image-k8s@v1}/action.yaml +0 -0
  36. /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{setup-prereq@v1 → common/setup-prereq@v1}/action.yaml +0 -0
  37. /package/src/target-templates/lang-variants-common/typescript/.github/actions/{build-image@v1 → common/build-image@v1}/action.yaml +0 -0
  38. /package/src/target-templates/lang-variants-common/typescript/.github/actions/{db-migrate@v1 → common/db-migrate@v1}/action.yaml +0 -0
  39. /package/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-cloudrun@v1 → common/deploy-image-cloudrun@v1}/action.yaml +0 -0
  40. /package/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-k8s@v1 → common/deploy-image-k8s@v1}/action.yaml +0 -0
  41. /package/src/target-templates/lang-variants-common/typescript/.github/actions/{setup-prereq@v1 → common/setup-prereq@v1}/action.yaml +0 -0
@@ -9,7 +9,8 @@ import { z } from "zod";
9
9
  var SUPPORTED_LANGUAGES = ["python", "node"];
10
10
  var constFileSchema = z.object({
11
11
  "project-name": z.string(),
12
- "infra": z.enum(["hetzner", "digitalocean", "gcloud"]),
12
+ "registry-infra": z.enum(["digitalocean", "gcp", "harbor"]),
13
+ "use-image-pull-secret": z.boolean().optional(),
13
14
  "image-versions-to-keep": z.number().optional(),
14
15
  "registry-base-url": z.string(),
15
16
  "registry-image-path-prefix": z.string().optional(),
@@ -2,7 +2,7 @@ import {
2
2
  getConst,
3
3
  getImageData,
4
4
  globEnvYamlFiles
5
- } from "./chunk-RZ46YYZZ.js";
5
+ } from "./chunk-6FEVIEFY.js";
6
6
 
7
7
  // src/cli/common.ts
8
8
  import chalk from "chalk";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConst
3
- } from "./chunk-RZ46YYZZ.js";
3
+ } from "./chunk-6FEVIEFY.js";
4
4
 
5
5
  // src/app-support/crypto/aes.ts
6
6
  import crypto from "crypto";
package/dist/devops.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import {
3
3
  InternalToken
4
- } from "./chunk-N7EX3HJH.js";
4
+ } from "./chunk-UZAJJUGJ.js";
5
5
  import {
6
6
  CLICommandParser,
7
7
  CommandExecutor,
@@ -24,7 +24,7 @@ import {
24
24
  printUsageAndExit,
25
25
  secretName,
26
26
  upsertConfigMapCommand
27
- } from "./chunk-WKP7EQNU.js";
27
+ } from "./chunk-QOZ6NZJC.js";
28
28
  import {
29
29
  IGNORED_PATHS,
30
30
  __export,
@@ -36,7 +36,7 @@ import {
36
36
  getWorkspace,
37
37
  globEnvYamlFiles,
38
38
  workspaceDirectoryForLanguage
39
- } from "./chunk-RZ46YYZZ.js";
39
+ } from "./chunk-6FEVIEFY.js";
40
40
 
41
41
  // src/devops.ts
42
42
  import { globSync as globSync2 } from "glob";
@@ -1103,7 +1103,7 @@ var consoleCommand = { command: "console", oneLiner: oneLiner6, keyExamples: key
1103
1103
 
1104
1104
  // src/cli/core/constant.ts
1105
1105
  var oneLiner7 = "Prints to stdout a constant from constant.yaml";
1106
- var keyExamples7 = `$ devops constant infra`;
1106
+ var keyExamples7 = `$ devops constant registry-infra`;
1107
1107
  var usage7 = `
1108
1108
  ${oneLiner7}
1109
1109
 
@@ -1741,12 +1741,12 @@ async function createFiles() {
1741
1741
  }
1742
1742
  tc.enableSubtitution(".devops/config/images.yaml");
1743
1743
  tc.setMessageGenerator(".envrc", envrcMessage);
1744
- const gitIgnore = gitIgnoreContent(userChoices.infraVariant, userChoices.usePython);
1744
+ const gitIgnore = gitIgnoreContent(userChoices.infraPreset, userChoices.usePython);
1745
1745
  tc.addGeneratedFile(".gitignore", gitIgnore);
1746
1746
  tc.setMessageGenerator(".gitignore", gitignoreMessageGen(gitIgnore));
1747
- tc.addCopiedFolder(`infra-variants/${userChoices.infraVariant}`, ".");
1747
+ tc.addCopiedFolder(`infra-variants/${userChoices.infraPreset}`, ".");
1748
1748
  tc.enableSubtitution(".devops/config/constants.yaml");
1749
- if (userChoices.infraVariant === "hetzner") {
1749
+ if (userChoices.infraPreset === "hetzner") {
1750
1750
  tc.enableSubtitution(".devops/infra/hetzner/harbor-cert.yaml");
1751
1751
  tc.enableSubtitution(".devops/infra/hetzner/harbor-values.yaml");
1752
1752
  tc.enableSubtitution(".devops/infra/hetzner/hcloud-config.yaml");
@@ -1804,12 +1804,12 @@ function packageJsonMessage(usePrisma) {
1804
1804
  "applications/**"${prismaMessage}
1805
1805
  ],`)}`;
1806
1806
  }
1807
- function gitIgnoreContent(infraVariant, usePython) {
1807
+ function gitIgnoreContent(infraPreset, usePython) {
1808
1808
  const common = `**/.env*
1809
1809
  config/kubeconfig
1810
1810
  tmp/**
1811
1811
  !tmp/**/.gitkeep`;
1812
- const gcloud = infraVariant === "gcloud" ? "config/gke_gcloud_auth_plugin_cache" : null;
1812
+ const gcloud = infraPreset === "gcloud" ? "config/gke_gcloud_auth_plugin_cache" : null;
1813
1813
  const python = usePython ? `venv/
1814
1814
  **/__pycache__` : null;
1815
1815
  return [common, gcloud, python].filter(Boolean).join("\n");
@@ -1854,12 +1854,12 @@ function getUserChoices(projectName) {
1854
1854
  },
1855
1855
  {
1856
1856
  type: "list",
1857
- name: "infraVariant",
1858
- message: "Where does your cluster run?",
1857
+ name: "infraPreset",
1858
+ message: "Select your infrastructure preset:",
1859
1859
  choices: [
1860
- { name: "Google Cloud", value: "gcloud" },
1861
- { name: "Digital Ocean", value: "digitalocean" },
1862
- { name: "Hetzner", value: "hetzner" }
1860
+ { name: "Google Cloud (GKE + GCP Registry)", value: "gcloud" },
1861
+ { name: "Digital Ocean (DO K8s + DO Registry)", value: "digitalocean" },
1862
+ { name: "Hetzner (Hetzner K8s + Harbor)", value: "hetzner" }
1863
1863
  ]
1864
1864
  },
1865
1865
  {
@@ -1867,21 +1867,21 @@ function getUserChoices(projectName) {
1867
1867
  name: "gcloudProjectId",
1868
1868
  message: "Enter the GCP project ID (default: 'changeme')",
1869
1869
  default: "changeme",
1870
- when: (answers) => answers.infraVariant === "gcloud"
1870
+ when: (answers) => answers.infraPreset === "gcloud"
1871
1871
  },
1872
1872
  {
1873
1873
  type: "input",
1874
1874
  name: "registryImagePathPrefix",
1875
1875
  message: (answers) => `Enter your Digital Ocean container registry name (default: '${answers.projectName}')`,
1876
1876
  default: (answers) => answers.projectName,
1877
- when: (answers) => answers.infraVariant === "digitalocean"
1877
+ when: (answers) => answers.infraPreset === "digitalocean"
1878
1878
  },
1879
1879
  {
1880
1880
  type: "input",
1881
1881
  name: "registryBaseUrl",
1882
1882
  message: (answers) => `Enter your registry base URL (default: 'registry.${answers.stagingDomain}')`,
1883
1883
  default: (answers) => `registry.${answers.stagingDomain}`,
1884
- when: (answers) => answers.infraVariant === "hetzner"
1884
+ when: (answers) => answers.infraPreset === "hetzner"
1885
1885
  },
1886
1886
  {
1887
1887
  type: "confirm",
@@ -2067,22 +2067,21 @@ function run11(cmdObj) {
2067
2067
  }
2068
2068
  var job = { oneLiner: oneLiner11, keyExamples: keyExamples11, run: run11 };
2069
2069
 
2070
- // src/libs/hetzner/reg-secret.ts
2070
+ // src/libs/registry/image-pull-secret.ts
2071
+ var SECRET_NAME = "external-registry-secret";
2072
+ var SOURCE_NAMESPACE = "default";
2071
2073
  function isApplicable() {
2072
- const infra = getConst("infra");
2073
- if (infra !== "hetzner") {
2074
- console.warn(
2075
- "Setting up registry permissions is only needed for Harbor in a Hetzner setup"
2076
- );
2074
+ const useImagePullSecret = getConst("use-image-pull-secret");
2075
+ if (!useImagePullSecret) {
2077
2076
  return false;
2078
2077
  }
2079
2078
  return true;
2080
2079
  }
2081
- function copySecretHarborToNamespace(monorepoEnv) {
2080
+ function copyRegistrySecretToNamespace(monorepoEnv) {
2082
2081
  if (!isApplicable()) return;
2083
- const cmd = kubectlCommand("get secret harbor-registry-secret -o json", {
2082
+ const cmd = kubectlCommand(`get secret ${SECRET_NAME} -o json`, {
2084
2083
  monorepoEnv,
2085
- namespace: "harbor"
2084
+ namespace: SOURCE_NAMESPACE
2086
2085
  });
2087
2086
  const secretStr = new CommandExecutor(cmd, { quiet: true }).exec();
2088
2087
  const secretJson = JSON.parse(secretStr);
@@ -2106,7 +2105,7 @@ function copySecretHarborToNamespace(monorepoEnv) {
2106
2105
  function patchServiceAccountImagePullSecret(monorepoEnv) {
2107
2106
  if (!isApplicable()) return;
2108
2107
  const cmd = kubectlCommand(
2109
- `patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-registry-secret"}]}'`,
2108
+ `patch serviceaccount default -p '{"imagePullSecrets": [{"name": "${SECRET_NAME}"}]}'`,
2110
2109
  { monorepoEnv }
2111
2110
  );
2112
2111
  new CommandExecutor(cmd, { quiet: true }).exec();
@@ -2127,8 +2126,8 @@ GENERAL USAGE
2127
2126
 
2128
2127
  'create' does the following:
2129
2128
  1. Creates the namepace
2130
- 2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
2131
- 3. On Hetzner, copies the Harbor secret to the namespace and patches the default service account to use it
2129
+ 2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
2130
+ 3. If use-image-pull-secret is true, copies the external-registry-secret to the namespace and patches the default service account to use it
2132
2131
 
2133
2132
  'delete' removes the namespace in kubernetes, which deletes all entities within it.
2134
2133
 
@@ -2143,7 +2142,7 @@ var handlers4 = {
2143
2142
  createNamespace(env2);
2144
2143
  createEmptyEnvSecret(env2);
2145
2144
  patchBaseSecret(env2);
2146
- copySecretHarborToNamespace(env2);
2145
+ copyRegistrySecretToNamespace(env2);
2147
2146
  patchServiceAccountImagePullSecret(env2);
2148
2147
  },
2149
2148
  delete(opts) {
@@ -2322,8 +2321,8 @@ function stargGarbageCollection(registryName) {
2322
2321
  new CommandExecutor(cmd).exec();
2323
2322
  }
2324
2323
  function prune(registryFullName, repoName, image2) {
2325
- const infra = getConst("infra");
2326
- if (infra !== "digitalocean") {
2324
+ const registryInfra = getConst("registry-infra");
2325
+ if (registryInfra !== "digitalocean") {
2327
2326
  console.warn(
2328
2327
  "Pruning is only supported for the DigitalOcean container registry"
2329
2328
  );
@@ -2375,7 +2374,7 @@ USAGE
2375
2374
  Prunes the repository of old images to enforce the "image-versions-to-keep" constant in config/constants.yaml:
2376
2375
  devops registry prune <image> --env <env>
2377
2376
 
2378
- This is only relevant when the "infra" constant is set to "digitalocean".
2377
+ This is only relevant when the "registry-infra" constant is set to "digitalocean".
2379
2378
 
2380
2379
  EXAMPLES
2381
2380
  ${keyExamples14}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,8 @@ declare const SUPPORTED_LANGUAGES: readonly ["python", "node"];
4
4
  type SupportedLanguages = typeof SUPPORTED_LANGUAGES[number];
5
5
  declare const constFileSchema: z.ZodObject<{
6
6
  "project-name": z.ZodString;
7
- infra: z.ZodEnum<["hetzner", "digitalocean", "gcloud"]>;
7
+ "registry-infra": z.ZodEnum<["digitalocean", "gcp", "harbor"]>;
8
+ "use-image-pull-secret": z.ZodOptional<z.ZodBoolean>;
8
9
  "image-versions-to-keep": z.ZodOptional<z.ZodNumber>;
9
10
  "registry-base-url": z.ZodString;
10
11
  "registry-image-path-prefix": z.ZodOptional<z.ZodString>;
@@ -14,20 +15,22 @@ declare const constFileSchema: z.ZodObject<{
14
15
  extensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
15
16
  }, "strip", z.ZodTypeAny, {
16
17
  "project-name": string;
17
- infra: "hetzner" | "digitalocean" | "gcloud";
18
+ "registry-infra": "digitalocean" | "gcp" | "harbor";
18
19
  "registry-base-url": string;
19
20
  "extra-remote-environments": string[];
20
21
  "extra-local-environments": string[];
22
+ "use-image-pull-secret"?: boolean | undefined;
21
23
  "image-versions-to-keep"?: number | undefined;
22
24
  "registry-image-path-prefix"?: string | undefined;
23
25
  "cloudrun-artifact-registry-repo-path"?: string | undefined;
24
26
  extensions?: string[] | undefined;
25
27
  }, {
26
28
  "project-name": string;
27
- infra: "hetzner" | "digitalocean" | "gcloud";
29
+ "registry-infra": "digitalocean" | "gcp" | "harbor";
28
30
  "registry-base-url": string;
29
31
  "extra-remote-environments": string[];
30
32
  "extra-local-environments": string[];
33
+ "use-image-pull-secret"?: boolean | undefined;
31
34
  "image-versions-to-keep"?: number | undefined;
32
35
  "registry-image-path-prefix"?: string | undefined;
33
36
  "cloudrun-artifact-registry-repo-path"?: string | undefined;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  InternalToken,
3
3
  decryptAes256Gcm,
4
4
  encryptAes256Gcm
5
- } from "./chunk-N7EX3HJH.js";
5
+ } from "./chunk-UZAJJUGJ.js";
6
6
  import {
7
7
  SUPPORTED_LANGUAGES,
8
8
  constFileSchema,
@@ -10,7 +10,7 @@ import {
10
10
  packageFileNodeSchema,
11
11
  packageFilePythonSchema,
12
12
  workspaces
13
- } from "./chunk-RZ46YYZZ.js";
13
+ } from "./chunk-6FEVIEFY.js";
14
14
 
15
15
  // src/app-support/discovery/dev-discovery-loader.ts
16
16
  var _portLookupByServiceName = null;
package/dist/plugins.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  kubectlCommand,
6
6
  pkgRoot,
7
7
  printUsageAndExit
8
- } from "./chunk-WKP7EQNU.js";
9
- import "./chunk-RZ46YYZZ.js";
8
+ } from "./chunk-QOZ6NZJC.js";
9
+ import "./chunk-6FEVIEFY.js";
10
10
 
11
11
  // src/plugins.ts
12
12
  import path from "path";
@@ -1,8 +1,8 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: digitalocean
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: digitalocean
6
6
 
7
7
  # Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
8
8
  image-versions-to-keep: 5
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to DigitalOcean K8s
35
35
  uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
@@ -42,16 +42,16 @@ jobs:
42
42
  with:
43
43
  access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
44
44
 
45
- # For deploying images to Cloud Run
46
- # - name: Connect to Cloud Run
47
- # uses: ./.github/actions/connect-to-cloud-run@v1
45
+ # For GCP Artifact Registry with OIDC (alternative to DOCR)
46
+ # - name: Connect to Artifact Registry with OIDC
47
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
48
48
  # with:
49
49
  # project_id: ${{ vars.GCP_PROJECT_ID }}
50
50
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
51
51
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
52
52
 
53
53
  - name: Build image
54
- uses: ./.github/actions/build-image@v1
54
+ uses: ./.github/actions/common/build-image@v1
55
55
  with:
56
56
  image_name: ${{ matrix.image_name }}
57
57
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -67,7 +67,7 @@ jobs:
67
67
  fetch-depth: 50
68
68
 
69
69
  - name: Setup prerequesites
70
- uses: ./.github/actions/setup-prereq@v1
70
+ uses: ./.github/actions/common/setup-prereq@v1
71
71
 
72
72
  - name: Connect to DigitalOcean K8s
73
73
  uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
@@ -80,22 +80,22 @@ jobs:
80
80
  with:
81
81
  access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
82
82
 
83
- # For deploying images to Cloud Run
84
- # - name: Connect to Cloud Run
85
- # uses: ./.github/actions/connect-to-cloud-run@v1
83
+ # For GCP Artifact Registry with OIDC (alternative to DOCR)
84
+ # - name: Connect to Artifact Registry with OIDC
85
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
86
86
  # with:
87
87
  # project_id: ${{ vars.GCP_PROJECT_ID }}
88
88
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
89
89
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
91
  - name: Run DB Migrate
92
- uses: ./.github/actions/db-migrate@v1
92
+ uses: ./.github/actions/common/db-migrate@v1
93
93
 
94
94
  # Repeat per image (it checks if the image is affected and deploys it if it is)
95
95
  - name: Deploy main node
96
- uses: ./.github/actions/deploy-image-k8s@v1
96
+ uses: ./.github/actions/common/deploy-image-k8s@v1
97
97
  with: { "image_name": "main-node" }
98
98
 
99
99
  - name: Deploy main python
100
- uses: ./.github/actions/deploy-image-k8s@v1
100
+ uses: ./.github/actions/common/deploy-image-k8s@v1
101
101
  with: { "image_name": "main-python" }
@@ -1,8 +1,8 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: gcloud
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: gcp
6
6
 
7
7
  registry-base-url: gcr.io
8
8
  # What comes before <image-name>:<tag>. Can be empty.
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to GKE
35
35
  uses: ./.github/actions/k8s/connect-to-gke@v1
@@ -40,22 +40,22 @@ jobs:
40
40
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
41
41
 
42
42
  - name: Connect to Artifact Registry
43
- uses: ./.github/actions/registry/connect-to-artifact-registry@v1
43
+ uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
44
44
  with:
45
45
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
46
46
  project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
47
47
  region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
48
48
 
49
- # For deploying images to Cloud Run
50
- # - name: Connect to Cloud Run
51
- # uses: ./.github/actions/connect-to-cloud-run@v1
49
+ # For GCP Artifact Registry with OIDC (alternative to service account key)
50
+ # - name: Connect to Artifact Registry with OIDC
51
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
52
52
  # with:
53
53
  # project_id: ${{ vars.GCP_PROJECT_ID }}
54
54
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
55
55
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
56
56
 
57
57
  - name: Build image
58
- uses: ./.github/actions/build-image@v1
58
+ uses: ./.github/actions/common/build-image@v1
59
59
  with:
60
60
  image_name: ${{ matrix.image_name }}
61
61
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -71,7 +71,7 @@ jobs:
71
71
  fetch-depth: 50
72
72
 
73
73
  - name: Setup prerequesites
74
- uses: ./.github/actions/setup-prereq@v1
74
+ uses: ./.github/actions/common/setup-prereq@v1
75
75
 
76
76
  - name: Connect to GKE
77
77
  uses: ./.github/actions/k8s/connect-to-gke@v1
@@ -82,28 +82,28 @@ jobs:
82
82
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
83
83
 
84
84
  - name: Connect to Artifact Registry
85
- uses: ./.github/actions/registry/connect-to-artifact-registry@v1
85
+ uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
86
86
  with:
87
87
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
88
88
  project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
89
89
  region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
- # For deploying images to Cloud Run
92
- # - name: Connect to Cloud Run
93
- # uses: ./.github/actions/connect-to-cloud-run@v1
91
+ # For GCP Artifact Registry with OIDC (alternative to service account key)
92
+ # - name: Connect to Artifact Registry with OIDC
93
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
94
94
  # with:
95
95
  # project_id: ${{ vars.GCP_PROJECT_ID }}
96
96
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
97
97
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
98
98
 
99
99
  - name: Run DB Migrate
100
- uses: ./.github/actions/db-migrate@v1
100
+ uses: ./.github/actions/common/db-migrate@v1
101
101
 
102
102
  # Repeat per image (it checks if the image is affected and deploys it if it is)
103
103
  - name: Deploy main node
104
- uses: ./.github/actions/deploy-image-k8s@v1
104
+ uses: ./.github/actions/common/deploy-image-k8s@v1
105
105
  with: { "image_name": "main-node" }
106
106
 
107
107
  - name: Deploy main python
108
- uses: ./.github/actions/deploy-image-k8s@v1
108
+ uses: ./.github/actions/common/deploy-image-k8s@v1
109
109
  with: { "image_name": "main-python" }
@@ -1,8 +1,12 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: hetzner
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: harbor
6
+
7
+ # When true, devops namespace create will copy external-registry-secret from default namespace
8
+ # and patch the default service account to use it. See docs/infra/RegistrySetup.md for details.
9
+ use-image-pull-secret: true
6
10
 
7
11
  # Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
8
12
  image-versions-to-keep: 5
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to Hetzner K8s
35
35
  uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
@@ -42,16 +42,16 @@ jobs:
42
42
  harbor_user: ${{ secrets.HARBOR_USER }}
43
43
  harbor_password: ${{ secrets.HARBOR_PASSWORD }}
44
44
 
45
- # For deploying images to Cloud Run
46
- # - name: Connect to Cloud Run
47
- # uses: ./.github/actions/connect-to-cloud-run@v1
45
+ # For GCP Artifact Registry with OIDC (alternative to Harbor)
46
+ # - name: Connect to Artifact Registry with OIDC
47
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
48
48
  # with:
49
49
  # project_id: ${{ vars.GCP_PROJECT_ID }}
50
50
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
51
51
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
52
52
 
53
53
  - name: Build image
54
- uses: ./.github/actions/build-image@v1
54
+ uses: ./.github/actions/common/build-image@v1
55
55
  with:
56
56
  image_name: ${{ matrix.image_name }}
57
57
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -67,7 +67,7 @@ jobs:
67
67
  fetch-depth: 50
68
68
 
69
69
  - name: Setup prerequesites
70
- uses: ./.github/actions/setup-prereq@v1
70
+ uses: ./.github/actions/common/setup-prereq@v1
71
71
 
72
72
  - name: Connect to Hetzner K8s
73
73
  uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
@@ -80,22 +80,22 @@ jobs:
80
80
  harbor_user: ${{ secrets.HARBOR_USER }}
81
81
  harbor_password: ${{ secrets.HARBOR_PASSWORD }}
82
82
 
83
- # For deploying images to Cloud Run
84
- # - name: Connect to Cloud Run
85
- # uses: ./.github/actions/connect-to-cloud-run@v1
83
+ # For GCP Artifact Registry with OIDC (alternative to Harbor)
84
+ # - name: Connect to Artifact Registry with OIDC
85
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
86
86
  # with:
87
87
  # project_id: ${{ vars.GCP_PROJECT_ID }}
88
88
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
89
89
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
91
  - name: Run DB Migrate
92
- uses: ./.github/actions/db-migrate@v1
92
+ uses: ./.github/actions/common/db-migrate@v1
93
93
 
94
94
  # Repeat per image (it checks if the image is affected and deploys it if it is)
95
95
  - name: Deploy main node
96
- uses: ./.github/actions/deploy-image-k8s@v1
96
+ uses: ./.github/actions/common/deploy-image-k8s@v1
97
97
  with: { "image_name": "main-node" }
98
98
 
99
99
  - name: Deploy main python
100
- uses: ./.github/actions/deploy-image-k8s@v1
100
+ uses: ./.github/actions/common/deploy-image-k8s@v1
101
101
  with: { "image_name": "main-python" }
@@ -0,0 +1,29 @@
1
+ name: "Connect to Artifact Registry with OIDC"
2
+ description: "Authenticates to Google Artifact Registry using Workload Identity Federation (OIDC)"
3
+ inputs:
4
+ project_id:
5
+ description: "Google Cloud project ID"
6
+ required: true
7
+ project_number:
8
+ description: "Google Cloud project number"
9
+ required: true
10
+ region:
11
+ description: "Google Cloud region where the Artifact Registry is located"
12
+ required: true
13
+ runs:
14
+ using: "composite"
15
+ steps:
16
+ - name: Auth to GCP via OIDC
17
+ uses: google-github-actions/auth@v2
18
+ with:
19
+ workload_identity_provider: projects/${{ inputs.project_number }}/locations/global/workloadIdentityPools/github/providers/github-oidc
20
+ service_account: gha-deployer@${{ inputs.project_id }}.iam.gserviceaccount.com
21
+ project_id: ${{ inputs.project_id }}
22
+
23
+ - name: Setup gcloud
24
+ uses: google-github-actions/setup-gcloud@v2
25
+
26
+ - name: Configure docker to use Artifact Registry
27
+ shell: bash
28
+ run: gcloud auth configure-docker ${{ inputs.region }}-docker.pkg.dev --quiet
29
+
@@ -1,5 +1,5 @@
1
- name: "Connect to Artifact Registry"
2
- description: "Authenticates to Google Artifact Registry"
1
+ name: "Connect to Artifact Registry with Service Account"
2
+ description: "Authenticates to Google Artifact Registry using a service account JSON key"
3
3
  inputs:
4
4
  service_account_key:
5
5
  description: "Google Cloud service account key in JSON format"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vaharoni/devops",
3
3
  "type": "module",
4
- "version": "1.2.18",
4
+ "version": "1.3.1",
5
5
  "description": "Devops utility",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -2,7 +2,7 @@ import { getConst } from "../../libs/config";
2
2
  import { CLICommandParser, printUsageAndExit } from "../common";
3
3
 
4
4
  const oneLiner = "Prints to stdout a constant from constant.yaml";
5
- const keyExamples = `$ devops constant infra`;
5
+ const keyExamples = `$ devops constant registry-infra`;
6
6
 
7
7
  const usage = `
8
8
  ${oneLiner}
@@ -3,7 +3,6 @@ import { InitGenerator, type InitGeneratorFileInfo } from "../../libs/init-gener
3
3
  import { CLICommandParser, printUsageAndExit } from "../common";
4
4
  import chalk from "chalk";
5
5
  import fs from 'fs-extra';
6
- import type { ConstFileSchema } from "../../types";
7
6
 
8
7
  const oneLiner =
9
8
  "Initializes the devops utility by copying template files to the current folder";
@@ -40,14 +39,14 @@ async function createFiles() {
40
39
  tc.setMessageGenerator(".envrc", envrcMessage);
41
40
 
42
41
  // gitignore
43
- const gitIgnore = gitIgnoreContent(userChoices.infraVariant, userChoices.usePython)
42
+ const gitIgnore = gitIgnoreContent(userChoices.infraPreset, userChoices.usePython)
44
43
  tc.addGeneratedFile(".gitignore", gitIgnore);
45
44
  tc.setMessageGenerator(".gitignore", gitignoreMessageGen(gitIgnore));
46
45
 
47
46
  // Infra variants
48
- tc.addCopiedFolder(`infra-variants/${userChoices.infraVariant}`, ".");
47
+ tc.addCopiedFolder(`infra-variants/${userChoices.infraPreset}`, ".");
49
48
  tc.enableSubtitution(".devops/config/constants.yaml");
50
- if (userChoices.infraVariant === "hetzner") {
49
+ if (userChoices.infraPreset === "hetzner") {
51
50
  tc.enableSubtitution(".devops/infra/hetzner/harbor-cert.yaml");
52
51
  tc.enableSubtitution(".devops/infra/hetzner/harbor-values.yaml");
53
52
  tc.enableSubtitution(".devops/infra/hetzner/hcloud-config.yaml");
@@ -119,13 +118,13 @@ function packageJsonMessage(usePrisma: boolean) {
119
118
  ],`)}`
120
119
  }
121
120
 
122
- function gitIgnoreContent(infraVariant: UserChoices["infraVariant"], usePython: boolean) {
121
+ function gitIgnoreContent(infraPreset: InfraPreset, usePython: boolean) {
123
122
  const common = `**/.env*
124
123
  config/kubeconfig
125
124
  tmp/**
126
125
  !tmp/**/.gitkeep`;
127
126
 
128
- const gcloud = infraVariant === 'gcloud'
127
+ const gcloud = infraPreset === 'gcloud'
129
128
  ? 'config/gke_gcloud_auth_plugin_cache'
130
129
  : null;
131
130
 
@@ -156,11 +155,13 @@ ${chalk.yellow(content)}`;
156
155
  }
157
156
  }
158
157
 
158
+ type InfraPreset = "gcloud" | "digitalocean" | "hetzner";
159
+
159
160
  type UserChoices = {
160
161
  projectName: string;
161
162
  stagingDomain: string;
162
163
  productionDomain: string;
163
- infraVariant: ConstFileSchema["infra"];
164
+ infraPreset: InfraPreset;
164
165
  gcloudProjectId?: string;
165
166
  registryImagePathPrefix?: string;
166
167
  registryBaseUrl?: string;
@@ -193,12 +194,12 @@ function getUserChoices(projectName: string | undefined): Promise<UserChoices> {
193
194
  },
194
195
  {
195
196
  type: "list",
196
- name: "infraVariant",
197
- message: "Where does your cluster run?",
197
+ name: "infraPreset",
198
+ message: "Select your infrastructure preset:",
198
199
  choices: [
199
- { name: "Google Cloud", value: "gcloud" },
200
- { name: "Digital Ocean", value: "digitalocean" },
201
- { name: "Hetzner", value: "hetzner" },
200
+ { name: "Google Cloud (GKE + GCP Registry)", value: "gcloud" },
201
+ { name: "Digital Ocean (DO K8s + DO Registry)", value: "digitalocean" },
202
+ { name: "Hetzner (Hetzner K8s + Harbor)", value: "hetzner" },
202
203
  ],
203
204
  },
204
205
  {
@@ -206,21 +207,21 @@ function getUserChoices(projectName: string | undefined): Promise<UserChoices> {
206
207
  name: "gcloudProjectId",
207
208
  message: "Enter the GCP project ID (default: 'changeme')",
208
209
  default: "changeme",
209
- when: (answers) => answers.infraVariant === "gcloud",
210
+ when: (answers) => answers.infraPreset === "gcloud",
210
211
  },
211
212
  {
212
213
  type: "input",
213
214
  name: "registryImagePathPrefix",
214
215
  message: (answers) => `Enter your Digital Ocean container registry name (default: '${answers.projectName}')`,
215
216
  default: (answers) => answers.projectName,
216
- when: (answers) => answers.infraVariant === "digitalocean",
217
+ when: (answers) => answers.infraPreset === "digitalocean",
217
218
  },
218
219
  {
219
220
  type: "input",
220
221
  name: "registryBaseUrl",
221
222
  message: (answers) => `Enter your registry base URL (default: 'registry.${answers.stagingDomain}')`,
222
223
  default: (answers) => `registry.${answers.stagingDomain}`,
223
- when: (answers) => answers.infraVariant === "hetzner",
224
+ when: (answers) => answers.infraPreset === "hetzner",
224
225
  },
225
226
  {
226
227
  type: "confirm",
@@ -1,8 +1,8 @@
1
1
  import { CLICommandParser, printUsageAndExit, StrongParams } from "../../../src/cli/common";
2
2
  import {
3
- copySecretHarborToNamespace,
3
+ copyRegistrySecretToNamespace,
4
4
  patchServiceAccountImagePullSecret,
5
- } from "../../../src/libs/hetzner/reg-secret";
5
+ } from "../../../src/libs/registry/image-pull-secret";
6
6
  import { checkEnvSetup, createEmptyEnvSecret, createNamespace, deleteNamespace, patchBaseSecret } from "../../libs/k8s-namespace";
7
7
 
8
8
  const oneLiner = "Creates the basic prerequisites for a monorepo";
@@ -20,8 +20,8 @@ GENERAL USAGE
20
20
 
21
21
  'create' does the following:
22
22
  1. Creates the namepace
23
- 2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
24
- 3. On Hetzner, copies the Harbor secret to the namespace and patches the default service account to use it
23
+ 2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
24
+ 3. If use-image-pull-secret is true, copies the external-registry-secret to the namespace and patches the default service account to use it
25
25
 
26
26
  'delete' removes the namespace in kubernetes, which deletes all entities within it.
27
27
 
@@ -37,7 +37,7 @@ const handlers = {
37
37
  createNamespace(env);
38
38
  createEmptyEnvSecret(env);
39
39
  patchBaseSecret(env);
40
- copySecretHarborToNamespace(env);
40
+ copyRegistrySecretToNamespace(env);
41
41
  patchServiceAccountImagePullSecret(env);
42
42
  },
43
43
  delete (opts: StrongParams) {
@@ -35,7 +35,7 @@ USAGE
35
35
  Prunes the repository of old images to enforce the "image-versions-to-keep" constant in config/constants.yaml:
36
36
  devops registry prune <image> --env <env>
37
37
 
38
- This is only relevant when the "infra" constant is set to "digitalocean".
38
+ This is only relevant when the "registry-infra" constant is set to "digitalocean".
39
39
 
40
40
  EXAMPLES
41
41
  ${keyExamples}
@@ -63,8 +63,8 @@ export function prune(
63
63
  repoName: string,
64
64
  image: string
65
65
  ) {
66
- const infra = getConst("infra");
67
- if (infra !== "digitalocean") {
66
+ const registryInfra = getConst("registry-infra");
67
+ if (registryInfra !== "digitalocean") {
68
68
  console.warn(
69
69
  "Pruning is only supported for the DigitalOcean container registry"
70
70
  );
@@ -3,23 +3,23 @@ import { getConst } from "../config";
3
3
  import { envToNamespace } from "../k8s-constants";
4
4
  import { kubectlCommand } from "../k8s-helpers";
5
5
 
6
+ const SECRET_NAME = "external-registry-secret";
7
+ const SOURCE_NAMESPACE = "default";
8
+
6
9
  function isApplicable() {
7
- const infra = getConst("infra");
8
- if (infra !== "hetzner") {
9
- console.warn(
10
- "Setting up registry permissions is only needed for Harbor in a Hetzner setup"
11
- );
10
+ const useImagePullSecret = getConst("use-image-pull-secret");
11
+ if (!useImagePullSecret) {
12
12
  return false;
13
13
  }
14
14
  return true;
15
15
  }
16
16
 
17
- export function copySecretHarborToNamespace(monorepoEnv: string) {
17
+ export function copyRegistrySecretToNamespace(monorepoEnv: string) {
18
18
  if (!isApplicable()) return;
19
19
 
20
- const cmd = kubectlCommand("get secret harbor-registry-secret -o json", {
20
+ const cmd = kubectlCommand(`get secret ${SECRET_NAME} -o json`, {
21
21
  monorepoEnv,
22
- namespace: "harbor",
22
+ namespace: SOURCE_NAMESPACE,
23
23
  });
24
24
  const secretStr = new CommandExecutor(cmd, { quiet: true }).exec();
25
25
  const secretJson = JSON.parse(secretStr);
@@ -47,7 +47,7 @@ export function patchServiceAccountImagePullSecret(monorepoEnv: string) {
47
47
  if (!isApplicable()) return;
48
48
 
49
49
  const cmd = kubectlCommand(
50
- `patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-registry-secret"}]}'`,
50
+ `patch serviceaccount default -p '{"imagePullSecrets": [{"name": "${SECRET_NAME}"}]}'`,
51
51
  { monorepoEnv }
52
52
  );
53
53
  new CommandExecutor(cmd, { quiet: true }).exec();
@@ -1,8 +1,8 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: digitalocean
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: digitalocean
6
6
 
7
7
  # Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
8
8
  image-versions-to-keep: 5
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to DigitalOcean K8s
35
35
  uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
@@ -42,16 +42,16 @@ jobs:
42
42
  with:
43
43
  access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
44
44
 
45
- # For deploying images to Cloud Run
46
- # - name: Connect to Cloud Run
47
- # uses: ./.github/actions/connect-to-cloud-run@v1
45
+ # For GCP Artifact Registry with OIDC (alternative to DOCR)
46
+ # - name: Connect to Artifact Registry with OIDC
47
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
48
48
  # with:
49
49
  # project_id: ${{ vars.GCP_PROJECT_ID }}
50
50
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
51
51
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
52
52
 
53
53
  - name: Build image
54
- uses: ./.github/actions/build-image@v1
54
+ uses: ./.github/actions/common/build-image@v1
55
55
  with:
56
56
  image_name: ${{ matrix.image_name }}
57
57
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -67,7 +67,7 @@ jobs:
67
67
  fetch-depth: 50
68
68
 
69
69
  - name: Setup prerequesites
70
- uses: ./.github/actions/setup-prereq@v1
70
+ uses: ./.github/actions/common/setup-prereq@v1
71
71
 
72
72
  - name: Connect to DigitalOcean K8s
73
73
  uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
@@ -80,22 +80,22 @@ jobs:
80
80
  with:
81
81
  access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
82
82
 
83
- # For deploying images to Cloud Run
84
- # - name: Connect to Cloud Run
85
- # uses: ./.github/actions/connect-to-cloud-run@v1
83
+ # For GCP Artifact Registry with OIDC (alternative to DOCR)
84
+ # - name: Connect to Artifact Registry with OIDC
85
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
86
86
  # with:
87
87
  # project_id: ${{ vars.GCP_PROJECT_ID }}
88
88
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
89
89
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
91
  - name: Run DB Migrate
92
- uses: ./.github/actions/db-migrate@v1
92
+ uses: ./.github/actions/common/db-migrate@v1
93
93
 
94
94
  # Repeat per image (it checks if the image is affected and deploys it if it is)
95
95
  - name: Deploy main node
96
- uses: ./.github/actions/deploy-image-k8s@v1
96
+ uses: ./.github/actions/common/deploy-image-k8s@v1
97
97
  with: { "image_name": "main-node" }
98
98
 
99
99
  - name: Deploy main python
100
- uses: ./.github/actions/deploy-image-k8s@v1
100
+ uses: ./.github/actions/common/deploy-image-k8s@v1
101
101
  with: { "image_name": "main-python" }
@@ -1,8 +1,8 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: gcloud
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: gcp
6
6
 
7
7
  registry-base-url: gcr.io
8
8
  # What comes before <image-name>:<tag>. Can be empty.
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to GKE
35
35
  uses: ./.github/actions/k8s/connect-to-gke@v1
@@ -40,22 +40,22 @@ jobs:
40
40
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
41
41
 
42
42
  - name: Connect to Artifact Registry
43
- uses: ./.github/actions/registry/connect-to-artifact-registry@v1
43
+ uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
44
44
  with:
45
45
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
46
46
  project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
47
47
  region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
48
48
 
49
- # For deploying images to Cloud Run
50
- # - name: Connect to Cloud Run
51
- # uses: ./.github/actions/connect-to-cloud-run@v1
49
+ # For GCP Artifact Registry with OIDC (alternative to service account key)
50
+ # - name: Connect to Artifact Registry with OIDC
51
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
52
52
  # with:
53
53
  # project_id: ${{ vars.GCP_PROJECT_ID }}
54
54
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
55
55
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
56
56
 
57
57
  - name: Build image
58
- uses: ./.github/actions/build-image@v1
58
+ uses: ./.github/actions/common/build-image@v1
59
59
  with:
60
60
  image_name: ${{ matrix.image_name }}
61
61
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -71,7 +71,7 @@ jobs:
71
71
  fetch-depth: 50
72
72
 
73
73
  - name: Setup prerequesites
74
- uses: ./.github/actions/setup-prereq@v1
74
+ uses: ./.github/actions/common/setup-prereq@v1
75
75
 
76
76
  - name: Connect to GKE
77
77
  uses: ./.github/actions/k8s/connect-to-gke@v1
@@ -82,28 +82,28 @@ jobs:
82
82
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
83
83
 
84
84
  - name: Connect to Artifact Registry
85
- uses: ./.github/actions/registry/connect-to-artifact-registry@v1
85
+ uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
86
86
  with:
87
87
  service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
88
88
  project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
89
89
  region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
- # For deploying images to Cloud Run
92
- # - name: Connect to Cloud Run
93
- # uses: ./.github/actions/connect-to-cloud-run@v1
91
+ # For GCP Artifact Registry with OIDC (alternative to service account key)
92
+ # - name: Connect to Artifact Registry with OIDC
93
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
94
94
  # with:
95
95
  # project_id: ${{ vars.GCP_PROJECT_ID }}
96
96
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
97
97
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
98
98
 
99
99
  - name: Run DB Migrate
100
- uses: ./.github/actions/db-migrate@v1
100
+ uses: ./.github/actions/common/db-migrate@v1
101
101
 
102
102
  # Repeat per image (it checks if the image is affected and deploys it if it is)
103
103
  - name: Deploy main node
104
- uses: ./.github/actions/deploy-image-k8s@v1
104
+ uses: ./.github/actions/common/deploy-image-k8s@v1
105
105
  with: { "image_name": "main-node" }
106
106
 
107
107
  - name: Deploy main python
108
- uses: ./.github/actions/deploy-image-k8s@v1
108
+ uses: ./.github/actions/common/deploy-image-k8s@v1
109
109
  with: { "image_name": "main-python" }
@@ -1,8 +1,12 @@
1
1
  # These will be used when generating kubernetes entities
2
2
  project-name: $PROJECT_NAME
3
3
 
4
- # Supported: hetzner, digitalocean, or gcloud
5
- infra: hetzner
4
+ # Registry infrastructure: digitalocean, gcp, or harbor
5
+ registry-infra: harbor
6
+
7
+ # When true, devops namespace create will copy external-registry-secret from default namespace
8
+ # and patch the default service account to use it. See docs/infra/RegistrySetup.md for details.
9
+ use-image-pull-secret: true
6
10
 
7
11
  # Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
8
12
  image-versions-to-keep: 5
@@ -9,7 +9,7 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
  packages: read
12
- # For deploying images to Cloud Run
12
+ # For OIDC authentication to GCP
13
13
  # id-token: write
14
14
 
15
15
  jobs:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 50
30
30
 
31
31
  - name: Setup prerequesites
32
- uses: ./.github/actions/setup-prereq@v1
32
+ uses: ./.github/actions/common/setup-prereq@v1
33
33
 
34
34
  - name: Connect to Hetzner K8s
35
35
  uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
@@ -42,16 +42,16 @@ jobs:
42
42
  harbor_user: ${{ secrets.HARBOR_USER }}
43
43
  harbor_password: ${{ secrets.HARBOR_PASSWORD }}
44
44
 
45
- # For deploying images to Cloud Run
46
- # - name: Connect to Cloud Run
47
- # uses: ./.github/actions/connect-to-cloud-run@v1
45
+ # For GCP Artifact Registry with OIDC (alternative to Harbor)
46
+ # - name: Connect to Artifact Registry with OIDC
47
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
48
48
  # with:
49
49
  # project_id: ${{ vars.GCP_PROJECT_ID }}
50
50
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
51
51
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
52
52
 
53
53
  - name: Build image
54
- uses: ./.github/actions/build-image@v1
54
+ uses: ./.github/actions/common/build-image@v1
55
55
  with:
56
56
  image_name: ${{ matrix.image_name }}
57
57
  cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
@@ -67,7 +67,7 @@ jobs:
67
67
  fetch-depth: 50
68
68
 
69
69
  - name: Setup prerequesites
70
- uses: ./.github/actions/setup-prereq@v1
70
+ uses: ./.github/actions/common/setup-prereq@v1
71
71
 
72
72
  - name: Connect to Hetzner K8s
73
73
  uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
@@ -80,22 +80,22 @@ jobs:
80
80
  harbor_user: ${{ secrets.HARBOR_USER }}
81
81
  harbor_password: ${{ secrets.HARBOR_PASSWORD }}
82
82
 
83
- # For deploying images to Cloud Run
84
- # - name: Connect to Cloud Run
85
- # uses: ./.github/actions/connect-to-cloud-run@v1
83
+ # For GCP Artifact Registry with OIDC (alternative to Harbor)
84
+ # - name: Connect to Artifact Registry with OIDC
85
+ # uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
86
86
  # with:
87
87
  # project_id: ${{ vars.GCP_PROJECT_ID }}
88
88
  # project_number: ${{ vars.GCP_PROJECT_NUMBER }}
89
89
  # region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
90
90
 
91
91
  - name: Run DB Migrate
92
- uses: ./.github/actions/db-migrate@v1
92
+ uses: ./.github/actions/common/db-migrate@v1
93
93
 
94
94
  # Repeat per image (it checks if the image is affected and deploys it if it is)
95
95
  - name: Deploy main node
96
- uses: ./.github/actions/deploy-image-k8s@v1
96
+ uses: ./.github/actions/common/deploy-image-k8s@v1
97
97
  with: { "image_name": "main-node" }
98
98
 
99
99
  - name: Deploy main python
100
- uses: ./.github/actions/deploy-image-k8s@v1
100
+ uses: ./.github/actions/common/deploy-image-k8s@v1
101
101
  with: { "image_name": "main-python" }
@@ -0,0 +1,29 @@
1
+ name: "Connect to Artifact Registry with OIDC"
2
+ description: "Authenticates to Google Artifact Registry using Workload Identity Federation (OIDC)"
3
+ inputs:
4
+ project_id:
5
+ description: "Google Cloud project ID"
6
+ required: true
7
+ project_number:
8
+ description: "Google Cloud project number"
9
+ required: true
10
+ region:
11
+ description: "Google Cloud region where the Artifact Registry is located"
12
+ required: true
13
+ runs:
14
+ using: "composite"
15
+ steps:
16
+ - name: Auth to GCP via OIDC
17
+ uses: google-github-actions/auth@v2
18
+ with:
19
+ workload_identity_provider: projects/${{ inputs.project_number }}/locations/global/workloadIdentityPools/github/providers/github-oidc
20
+ service_account: gha-deployer@${{ inputs.project_id }}.iam.gserviceaccount.com
21
+ project_id: ${{ inputs.project_id }}
22
+
23
+ - name: Setup gcloud
24
+ uses: google-github-actions/setup-gcloud@v2
25
+
26
+ - name: Configure docker to use Artifact Registry
27
+ shell: bash
28
+ run: gcloud auth configure-docker ${{ inputs.region }}-docker.pkg.dev --quiet
29
+
@@ -1,5 +1,5 @@
1
- name: "Connect to Artifact Registry"
2
- description: "Authenticates to Google Artifact Registry"
1
+ name: "Connect to Artifact Registry with Service Account"
2
+ description: "Authenticates to Google Artifact Registry using a service account JSON key"
3
3
  inputs:
4
4
  service_account_key:
5
5
  description: "Google Cloud service account key in JSON format"
@@ -7,7 +7,8 @@ export type SupportedLanguages = typeof SUPPORTED_LANGUAGES[number];
7
7
 
8
8
  export const constFileSchema = z.object({
9
9
  "project-name": z.string(),
10
- "infra": z.enum(["hetzner", "digitalocean", "gcloud"]),
10
+ "registry-infra": z.enum(["digitalocean", "gcp", "harbor"]),
11
+ "use-image-pull-secret": z.boolean().optional(),
11
12
  "image-versions-to-keep": z.number().optional(),
12
13
  "registry-base-url": z.string(),
13
14
  "registry-image-path-prefix": z.string().optional(),