@rizom/ops 0.2.0-alpha.12 → 0.2.0-alpha.120

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 (43) hide show
  1. package/README.md +7 -3
  2. package/dist/age-key-bootstrap.d.ts +17 -0
  3. package/dist/brains-ops.js +281 -160
  4. package/dist/cert-bootstrap.d.ts +3 -3
  5. package/dist/content-repo.d.ts +4 -0
  6. package/dist/deploy.js +3 -170
  7. package/dist/entries/deploy.d.ts +2 -2
  8. package/dist/index.d.ts +4 -0
  9. package/dist/index.js +280 -159
  10. package/dist/load-registry.d.ts +12 -3
  11. package/dist/observed-status.d.ts +1 -1
  12. package/dist/origin-ca.d.ts +1 -1
  13. package/dist/parse-args.d.ts +2 -0
  14. package/dist/push-secrets.d.ts +1 -1
  15. package/dist/run-command.d.ts +1 -2
  16. package/dist/schema.d.ts +64 -10
  17. package/dist/secrets-encrypt.d.ts +32 -0
  18. package/dist/secrets-push.d.ts +1 -1
  19. package/dist/ssh-key-bootstrap.d.ts +1 -1
  20. package/dist/user-add.d.ts +15 -0
  21. package/dist/verify-user.d.ts +19 -0
  22. package/package.json +7 -3
  23. package/templates/rover-pilot/.env.schema +21 -2
  24. package/templates/rover-pilot/.github/workflows/build.yml +13 -5
  25. package/templates/rover-pilot/.github/workflows/deploy.yml +64 -27
  26. package/templates/rover-pilot/.github/workflows/reconcile.yml +16 -2
  27. package/templates/rover-pilot/README.md +6 -3
  28. package/templates/rover-pilot/deploy/scripts/decrypt-user-secrets.ts +79 -0
  29. package/templates/rover-pilot/deploy/scripts/provision-server.ts +1 -1
  30. package/templates/rover-pilot/deploy/scripts/resolve-deploy-handles.ts +15 -6
  31. package/templates/rover-pilot/deploy/scripts/resolve-user-config.ts +12 -12
  32. package/templates/rover-pilot/deploy/scripts/update-dns.ts +14 -4
  33. package/templates/rover-pilot/docs/onboarding-checklist.md +43 -14
  34. package/templates/rover-pilot/docs/operator-playbook.md +159 -10
  35. package/templates/rover-pilot/docs/user-onboarding.md +156 -295
  36. package/templates/rover-pilot/package.json +3 -0
  37. package/templates/rover-pilot/pilot.yaml +3 -0
  38. package/templates/rover-pilot/users/alice.yaml +2 -1
  39. package/dist/user-secret-names.d.ts +0 -6
  40. package/templates/rover-pilot/.kamal/hooks/pre-deploy +0 -9
  41. package/templates/rover-pilot/deploy/Caddyfile +0 -72
  42. package/templates/rover-pilot/deploy/Dockerfile +0 -38
  43. package/templates/rover-pilot/deploy/kamal/deploy.yml +0 -40
@@ -13,6 +13,7 @@ export interface ResolvedCohort {
13
13
  brainVersionOverride?: string;
14
14
  presetOverride?: PilotPreset;
15
15
  aiApiKeyOverride?: string;
16
+ gitSyncTokenOverride?: string;
16
17
  }
17
18
  export interface ResolvedAnchorProfileSocialLink {
18
19
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
@@ -27,6 +28,13 @@ export interface ResolvedAnchorProfile {
27
28
  story?: string;
28
29
  socialLinks?: ResolvedAnchorProfileSocialLink[];
29
30
  }
31
+ export interface ResolvedSetupDelivery {
32
+ delivery: "email";
33
+ email: string;
34
+ }
35
+ export interface ResolvedAtprotoConfig {
36
+ identifier: string;
37
+ }
30
38
  export interface ResolvedUserIdentity {
31
39
  handle: string;
32
40
  cohort: string;
@@ -36,7 +44,11 @@ export interface ResolvedUserIdentity {
36
44
  domain: string;
37
45
  contentRepo: string;
38
46
  discordEnabled: boolean;
47
+ discordAnchorUserId?: string;
39
48
  effectiveAiApiKey: string;
49
+ effectiveGitSyncToken: string;
50
+ setup?: ResolvedSetupDelivery;
51
+ atproto?: ResolvedAtprotoConfig;
40
52
  anchorProfile: ResolvedAnchorProfile;
41
53
  snapshotStatus: SnapshotStatus;
42
54
  }
@@ -54,7 +66,4 @@ export interface PilotRegistry {
54
66
  cohorts: ResolvedCohort[];
55
67
  users: ResolvedUser[];
56
68
  }
57
- declare class PilotRegistryError extends Error {
58
- }
59
69
  export declare function loadPilotRegistry(rootDir: string, options?: LoadPilotRegistryOptions): Promise<PilotRegistry>;
60
- export { PilotRegistryError };
@@ -1,4 +1,4 @@
1
- import type { FetchLike } from "@brains/utils/origin-ca";
1
+ import type { FetchLike } from "@brains/deploy-support/origin-ca";
2
2
  import type { ObservedUserStatus, ResolvedUserIdentity } from "./load-registry";
3
3
  export interface LookupResult {
4
4
  address: string;
@@ -1 +1 @@
1
- export { createOriginCertificateRequest, generateOriginKeyPair, issueCloudflareOriginCertificate, setCloudflareZoneSslStrict, type CloudflareOriginCaResult, type FetchLike, type OriginCertificateRequest, type OriginKeyPair, } from "@brains/utils/origin-ca";
1
+ export { createOriginCertificateRequest, generateOriginKeyPair, issueCloudflareOriginCertificate, setCloudflareZoneSslStrict, type CloudflareOriginCaResult, type FetchLike, type OriginCertificateRequest, type OriginKeyPair, } from "@brains/deploy-support/origin-ca";
@@ -6,6 +6,8 @@ export interface ParsedArgs {
6
6
  version?: boolean | undefined;
7
7
  dryRun?: boolean | undefined;
8
8
  pushTo?: string | undefined;
9
+ cohort?: string | undefined;
10
+ anchorId?: string | undefined;
9
11
  };
10
12
  }
11
13
  export declare function parseArgs(argv: string[]): ParsedArgs;
@@ -5,5 +5,5 @@ export interface PushSecretsOptions {
5
5
  runCommand?: RunCommand | undefined;
6
6
  logger?: ((message: string) => void) | undefined;
7
7
  }
8
- export declare function pushSecretsToBackend(target: PushTarget, secrets: readonly SecretPair[], options?: PushSecretsOptions): Promise<void>;
8
+ export declare function pushSecretsToBackend(_target: PushTarget, secrets: readonly SecretPair[], options?: PushSecretsOptions): Promise<void>;
9
9
  export { normalizePushTarget };
@@ -1,4 +1,4 @@
1
- import type { FetchLike } from "@brains/utils/origin-ca";
1
+ import type { FetchLike } from "@brains/deploy-support/origin-ca";
2
2
  import type { LoadPilotRegistryOptions } from "./load-registry";
3
3
  import { type LookupHost } from "./observed-status";
4
4
  import type { ParsedArgs } from "./parse-args";
@@ -15,7 +15,6 @@ export interface CommandDependencies extends LoadPilotRegistryOptions {
15
15
  logger?: ((message: string) => void) | undefined;
16
16
  fetchImpl?: FetchLike | undefined;
17
17
  lookupHost?: LookupHost | undefined;
18
- secretRunCommand?: OpsRunCommand | undefined;
19
18
  bootstrapRunCommand?: OpsRunCommand | undefined;
20
19
  sshKeygen?: SshKeygen | undefined;
21
20
  }
package/dist/schema.d.ts CHANGED
@@ -3,6 +3,7 @@ export declare const presetSchema: z.ZodEnum<["core", "default", "pro"]>;
3
3
  export declare const exactVersionSchema: z.ZodString;
4
4
  export declare const handleSchema: z.ZodString;
5
5
  export declare const secretNameSchema: z.ZodString;
6
+ export declare const agePublicKeySchema: z.ZodString;
6
7
  export declare const pilotSchema: z.ZodObject<{
7
8
  schemaVersion: z.ZodLiteral<1>;
8
9
  brainVersion: z.ZodString;
@@ -12,7 +13,11 @@ export declare const pilotSchema: z.ZodObject<{
12
13
  domainSuffix: z.ZodString;
13
14
  preset: z.ZodEnum<["core", "default", "pro"]>;
14
15
  aiApiKey: z.ZodString;
16
+ gitSyncToken: z.ZodString;
17
+ contentRepoAdminToken: z.ZodString;
18
+ agePublicKey: z.ZodString;
15
19
  }, "strict", z.ZodTypeAny, {
20
+ agePublicKey: string;
16
21
  schemaVersion: 1;
17
22
  brainVersion: string;
18
23
  model: "rover";
@@ -21,7 +26,10 @@ export declare const pilotSchema: z.ZodObject<{
21
26
  domainSuffix: string;
22
27
  preset: "default" | "core" | "pro";
23
28
  aiApiKey: string;
29
+ gitSyncToken: string;
30
+ contentRepoAdminToken: string;
24
31
  }, {
32
+ agePublicKey: string;
25
33
  schemaVersion: 1;
26
34
  brainVersion: string;
27
35
  model: "rover";
@@ -30,17 +38,40 @@ export declare const pilotSchema: z.ZodObject<{
30
38
  domainSuffix: string;
31
39
  preset: "default" | "core" | "pro";
32
40
  aiApiKey: string;
41
+ gitSyncToken: string;
42
+ contentRepoAdminToken: string;
33
43
  }>;
34
44
  export declare const userSchema: z.ZodObject<{
35
45
  handle: z.ZodString;
36
46
  discord: z.ZodObject<{
37
47
  enabled: z.ZodBoolean;
48
+ anchorUserId: z.ZodOptional<z.ZodString>;
38
49
  }, "strict", z.ZodTypeAny, {
39
50
  enabled: boolean;
51
+ anchorUserId?: string | undefined;
40
52
  }, {
41
53
  enabled: boolean;
54
+ anchorUserId?: string | undefined;
42
55
  }>;
43
56
  aiApiKeyOverride: z.ZodOptional<z.ZodString>;
57
+ gitSyncTokenOverride: z.ZodOptional<z.ZodString>;
58
+ setup: z.ZodOptional<z.ZodObject<{
59
+ delivery: z.ZodLiteral<"email">;
60
+ email: z.ZodString;
61
+ }, "strict", z.ZodTypeAny, {
62
+ email: string;
63
+ delivery: "email";
64
+ }, {
65
+ email: string;
66
+ delivery: "email";
67
+ }>>;
68
+ atproto: z.ZodOptional<z.ZodObject<{
69
+ identifier: z.ZodString;
70
+ }, "strict", z.ZodTypeAny, {
71
+ identifier: string;
72
+ }, {
73
+ identifier: string;
74
+ }>>;
44
75
  anchorProfile: z.ZodOptional<z.ZodObject<{
45
76
  name: z.ZodOptional<z.ZodString>;
46
77
  description: z.ZodOptional<z.ZodString>;
@@ -52,34 +83,34 @@ export declare const userSchema: z.ZodObject<{
52
83
  url: z.ZodString;
53
84
  label: z.ZodOptional<z.ZodString>;
54
85
  }, "strict", z.ZodTypeAny, {
55
- url: string;
56
86
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
87
+ url: string;
57
88
  label?: string | undefined;
58
89
  }, {
59
- url: string;
60
90
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
91
+ url: string;
61
92
  label?: string | undefined;
62
93
  }>, "many">>;
63
94
  }, "strict", z.ZodTypeAny, {
95
+ name?: string | undefined;
64
96
  email?: string | undefined;
65
97
  website?: string | undefined;
66
- name?: string | undefined;
67
98
  description?: string | undefined;
68
99
  story?: string | undefined;
69
100
  socialLinks?: {
70
- url: string;
71
101
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
102
+ url: string;
72
103
  label?: string | undefined;
73
104
  }[] | undefined;
74
105
  }, {
106
+ name?: string | undefined;
75
107
  email?: string | undefined;
76
108
  website?: string | undefined;
77
- name?: string | undefined;
78
109
  description?: string | undefined;
79
110
  story?: string | undefined;
80
111
  socialLinks?: {
81
- url: string;
82
112
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
113
+ url: string;
83
114
  label?: string | undefined;
84
115
  }[] | undefined;
85
116
  }>>;
@@ -87,17 +118,26 @@ export declare const userSchema: z.ZodObject<{
87
118
  handle: string;
88
119
  discord: {
89
120
  enabled: boolean;
121
+ anchorUserId?: string | undefined;
90
122
  };
91
123
  aiApiKeyOverride?: string | undefined;
124
+ gitSyncTokenOverride?: string | undefined;
125
+ setup?: {
126
+ email: string;
127
+ delivery: "email";
128
+ } | undefined;
129
+ atproto?: {
130
+ identifier: string;
131
+ } | undefined;
92
132
  anchorProfile?: {
133
+ name?: string | undefined;
93
134
  email?: string | undefined;
94
135
  website?: string | undefined;
95
- name?: string | undefined;
96
136
  description?: string | undefined;
97
137
  story?: string | undefined;
98
138
  socialLinks?: {
99
- url: string;
100
139
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
140
+ url: string;
101
141
  label?: string | undefined;
102
142
  }[] | undefined;
103
143
  } | undefined;
@@ -105,17 +145,26 @@ export declare const userSchema: z.ZodObject<{
105
145
  handle: string;
106
146
  discord: {
107
147
  enabled: boolean;
148
+ anchorUserId?: string | undefined;
108
149
  };
109
150
  aiApiKeyOverride?: string | undefined;
151
+ gitSyncTokenOverride?: string | undefined;
152
+ setup?: {
153
+ email: string;
154
+ delivery: "email";
155
+ } | undefined;
156
+ atproto?: {
157
+ identifier: string;
158
+ } | undefined;
110
159
  anchorProfile?: {
160
+ name?: string | undefined;
111
161
  email?: string | undefined;
112
162
  website?: string | undefined;
113
- name?: string | undefined;
114
163
  description?: string | undefined;
115
164
  story?: string | undefined;
116
165
  socialLinks?: {
117
- url: string;
118
166
  platform: "github" | "instagram" | "linkedin" | "email" | "website";
167
+ url: string;
119
168
  label?: string | undefined;
120
169
  }[] | undefined;
121
170
  } | undefined;
@@ -125,24 +174,29 @@ export declare const cohortSchema: z.ZodEffects<z.ZodObject<{
125
174
  brainVersionOverride: z.ZodOptional<z.ZodString>;
126
175
  presetOverride: z.ZodOptional<z.ZodEnum<["core", "default", "pro"]>>;
127
176
  aiApiKeyOverride: z.ZodOptional<z.ZodString>;
177
+ gitSyncTokenOverride: z.ZodOptional<z.ZodString>;
128
178
  }, "strict", z.ZodTypeAny, {
129
179
  members: string[];
130
180
  aiApiKeyOverride?: string | undefined;
181
+ gitSyncTokenOverride?: string | undefined;
131
182
  brainVersionOverride?: string | undefined;
132
183
  presetOverride?: "default" | "core" | "pro" | undefined;
133
184
  }, {
134
185
  members: string[];
135
186
  aiApiKeyOverride?: string | undefined;
187
+ gitSyncTokenOverride?: string | undefined;
136
188
  brainVersionOverride?: string | undefined;
137
189
  presetOverride?: "default" | "core" | "pro" | undefined;
138
190
  }>, {
139
191
  members: string[];
140
192
  aiApiKeyOverride?: string | undefined;
193
+ gitSyncTokenOverride?: string | undefined;
141
194
  brainVersionOverride?: string | undefined;
142
195
  presetOverride?: "default" | "core" | "pro" | undefined;
143
196
  }, {
144
197
  members: string[];
145
198
  aiApiKeyOverride?: string | undefined;
199
+ gitSyncTokenOverride?: string | undefined;
146
200
  brainVersionOverride?: string | undefined;
147
201
  presetOverride?: "default" | "core" | "pro" | undefined;
148
202
  }>;
@@ -0,0 +1,32 @@
1
+ import { z } from "@brains/utils";
2
+ declare const encryptedUserSecretsSchema: z.ZodObject<{
3
+ gitSyncToken: z.ZodOptional<z.ZodString>;
4
+ discordBotToken: z.ZodOptional<z.ZodString>;
5
+ aiApiKey: z.ZodOptional<z.ZodString>;
6
+ atprotoAppPassword: z.ZodOptional<z.ZodString>;
7
+ }, "strict", z.ZodTypeAny, {
8
+ aiApiKey?: string | undefined;
9
+ gitSyncToken?: string | undefined;
10
+ discordBotToken?: string | undefined;
11
+ atprotoAppPassword?: string | undefined;
12
+ }, {
13
+ aiApiKey?: string | undefined;
14
+ gitSyncToken?: string | undefined;
15
+ discordBotToken?: string | undefined;
16
+ atprotoAppPassword?: string | undefined;
17
+ }>;
18
+ export type EncryptedUserSecrets = z.infer<typeof encryptedUserSecretsSchema>;
19
+ export interface SecretsEncryptOptions {
20
+ env?: NodeJS.ProcessEnv | undefined;
21
+ logger?: ((message: string) => void) | undefined;
22
+ dryRun?: boolean | undefined;
23
+ }
24
+ export interface SecretsEncryptResult {
25
+ encryptedPath: string;
26
+ plaintextPath: string;
27
+ deletedPlaintext: boolean;
28
+ encryptedKeys: Array<keyof EncryptedUserSecrets>;
29
+ dryRun?: boolean | undefined;
30
+ }
31
+ export declare function encryptPilotSecrets(rootDir: string, handle: string, options?: SecretsEncryptOptions): Promise<SecretsEncryptResult>;
32
+ export {};
@@ -10,4 +10,4 @@ export interface SecretsPushResult {
10
10
  skippedKeys: string[];
11
11
  dryRun?: boolean | undefined;
12
12
  }
13
- export declare function pushPilotSecrets(rootDir: string, handle: string, options?: SecretsPushOptions): Promise<SecretsPushResult>;
13
+ export declare function pushPilotSecrets(rootDir: string, options?: SecretsPushOptions): Promise<SecretsPushResult>;
@@ -1,4 +1,4 @@
1
- import { type FetchLike } from "@brains/utils/origin-ca";
1
+ import { type FetchLike } from "@brains/deploy-support/origin-ca";
2
2
  import { type RunCommand } from "./run-subprocess";
3
3
  export interface SshKeyBootstrapOptions {
4
4
  env?: NodeJS.ProcessEnv | undefined;
@@ -0,0 +1,15 @@
1
+ export interface AddPilotUserOptions {
2
+ cohort: string;
3
+ anchorId?: string | undefined;
4
+ }
5
+ export interface AddPilotUserResult {
6
+ handle: string;
7
+ cohort: string;
8
+ userPath: string;
9
+ secretsTemplatePath: string;
10
+ cohortPath: string;
11
+ createdUser: boolean;
12
+ createdSecretsTemplate: boolean;
13
+ addedToCohort: boolean;
14
+ }
15
+ export declare function addPilotUser(rootDir: string, handle: string, options: AddPilotUserOptions): Promise<AddPilotUserResult>;
@@ -0,0 +1,19 @@
1
+ import type { FetchLike } from "@brains/deploy-support/origin-ca";
2
+ import { type ResolvedUser } from "./load-registry";
3
+ export interface VerifyPilotUserOptions {
4
+ fetchImpl?: FetchLike;
5
+ logger?: (message: string) => void;
6
+ }
7
+ export interface FailedCheck {
8
+ name: string;
9
+ message: string;
10
+ }
11
+ export interface VerifyPilotUserResult {
12
+ handle: string;
13
+ preset: ResolvedUser["preset"];
14
+ domain: string;
15
+ contentRepo: string;
16
+ checks: string[];
17
+ failedChecks: FailedCheck[];
18
+ }
19
+ export declare function verifyPilotUser(rootDir: string, handle: string, options?: VerifyPilotUserOptions): Promise<VerifyPilotUserResult>;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.2.0-alpha.12",
7
+ "version": "0.2.0-alpha.120",
8
8
  "type": "module",
9
9
  "exports": {
10
10
  ".": {
@@ -32,10 +32,14 @@
32
32
  "typecheck": "tsc --noEmit",
33
33
  "lint": "eslint . --ext .ts",
34
34
  "lint:fix": "eslint . --ext .ts --fix",
35
- "test": "bun test"
35
+ "test": "bun run build && bun test --timeout 20000",
36
+ "test:smoke": "bun run build && RUN_SMOKE_TESTS=1 bun test --timeout 60000"
37
+ },
38
+ "dependencies": {
39
+ "age-encryption": "^0.3.0"
36
40
  },
37
- "dependencies": {},
38
41
  "devDependencies": {
42
+ "@brains/deploy-support": "workspace:*",
39
43
  "@brains/eslint-config": "workspace:*",
40
44
  "@brains/typescript-config": "workspace:*",
41
45
  "@brains/utils": "workspace:*",
@@ -4,21 +4,40 @@
4
4
  # ----------
5
5
 
6
6
  # AI provider
7
+ # Shared GitHub secret by default; a per-user override may come from the decrypted
8
+ # users/<handle>.secrets.yaml.age file at deploy time.
7
9
  # @required @sensitive
8
10
  AI_API_KEY=
9
11
 
10
12
  # Git sync
13
+ # Comes from the decrypted users/<handle>.secrets.yaml.age file.
11
14
  # @required @sensitive
12
15
  GIT_SYNC_TOKEN=
13
16
 
14
- # MCP interface
17
+ # Content repo administration
18
+ # Local/operator secret only. Used by brains-ops to create missing GitHub repos;
19
+ # do not deploy it into Rover runtime config.
15
20
  # @required @sensitive
16
- MCP_AUTH_TOKEN=
21
+ CONTENT_REPO_ADMIN_TOKEN=
17
22
 
18
23
  # Discord (optional, per-user)
24
+ # Comes from the decrypted users/<handle>.secrets.yaml.age file when enabled.
19
25
  # @sensitive
20
26
  DISCORD_BOT_TOKEN=
21
27
 
28
+ # AT Protocol publishing/discovery (optional, per-user)
29
+ # Comes from the decrypted users/<handle>.secrets.yaml.age file when configured.
30
+ # @sensitive
31
+ ATPROTO_APP_PASSWORD=
32
+
33
+ # Setup email delivery (optional, shared)
34
+ # Used when a user file declares setup.delivery: email.
35
+ # @sensitive
36
+ SETUP_EMAIL_API_KEY=
37
+
38
+ # @sensitive
39
+ SETUP_EMAIL_FROM=
40
+
22
41
  # ---- deploy/provision vars ----
23
42
 
24
43
  # @required @sensitive
@@ -2,6 +2,11 @@ name: Build
2
2
 
3
3
  on:
4
4
  workflow_dispatch:
5
+ inputs:
6
+ brain_version:
7
+ description: Brain version to build; defaults to pilot.yaml brainVersion
8
+ required: false
9
+ type: string
5
10
  push:
6
11
  branches: ["main"]
7
12
  paths:
@@ -23,7 +28,10 @@ jobs:
23
28
 
24
29
  - name: Extract image metadata inputs
25
30
  run: |
26
- BRAIN_VERSION="$(grep '^brainVersion:' pilot.yaml | sed 's/^brainVersion:[[:space:]]*//' | tr -d '"' | tr -d "'")"
31
+ BRAIN_VERSION="${{ inputs.brain_version || '' }}"
32
+ if [ -z "$BRAIN_VERSION" ]; then
33
+ BRAIN_VERSION="$(grep '^brainVersion:' pilot.yaml | sed 's/^brainVersion:[[:space:]]*//' | tr -d '"' | tr -d "'")"
34
+ fi
27
35
  if [ -z "$BRAIN_VERSION" ]; then
28
36
  echo "Missing brainVersion in pilot.yaml" >&2
29
37
  exit 1
@@ -32,25 +40,25 @@ jobs:
32
40
  echo "IMAGE_REPOSITORY=ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}" >> "$GITHUB_ENV"
33
41
 
34
42
  - name: Set up Docker Buildx
35
- uses: docker/setup-buildx-action@v3
43
+ uses: docker/setup-buildx-action@v4
36
44
 
37
45
  - name: Extract image metadata
38
46
  id: meta
39
- uses: docker/metadata-action@v5
47
+ uses: docker/metadata-action@v6
40
48
  with:
41
49
  images: ${{ env.IMAGE_REPOSITORY }}
42
50
  tags: |
43
51
  type=raw,value=brain-${{ env.BRAIN_VERSION }}
44
52
 
45
53
  - name: Log in to GHCR
46
- uses: docker/login-action@v3
54
+ uses: docker/login-action@v4
47
55
  with:
48
56
  registry: ghcr.io
49
57
  username: ${{ github.actor }}
50
58
  password: ${{ secrets.GITHUB_TOKEN }}
51
59
 
52
60
  - name: Build and push image
53
- uses: docker/build-push-action@v6
61
+ uses: docker/build-push-action@v7
54
62
  with:
55
63
  context: .
56
64
  file: deploy/Dockerfile