@microagi/alchemy-gcp 0.8.0 → 0.8.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.
- package/lib/ArtifactRegistry/Operations.d.ts +2 -2
- package/lib/ArtifactRegistry/Operations.d.ts.map +1 -1
- package/lib/ArtifactRegistry/Repository.d.ts +1 -1
- package/lib/ArtifactRegistry/Validation.d.ts.map +1 -1
- package/lib/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Auth/AuthProvider.js.map +1 -1
- package/lib/Auth/Credentials.d.ts +1 -1
- package/lib/Auth/Credentials.d.ts.map +1 -1
- package/lib/CloudResourceManager/Project.d.ts +1 -1
- package/lib/CloudResourceManager/ProjectIamMember.d.ts.map +1 -1
- package/lib/Compute/Address.d.ts +1 -1
- package/lib/Compute/Firewall.d.ts +1 -1
- package/lib/Compute/ForwardingRule.d.ts +1 -1
- package/lib/Compute/GlobalAddress.d.ts +1 -1
- package/lib/Compute/Network.d.ts +1 -1
- package/lib/Compute/Network.d.ts.map +1 -1
- package/lib/Compute/Operations.d.ts +4 -4
- package/lib/Compute/Operations.d.ts.map +1 -1
- package/lib/Compute/Subnetwork.d.ts +1 -1
- package/lib/Compute/SubnetworkIamMember.d.ts.map +1 -1
- package/lib/Container/Cluster.d.ts +1 -1
- package/lib/Container/NodePool.d.ts +11 -1
- package/lib/Container/NodePool.d.ts.map +1 -1
- package/lib/Container/NodePool.js +4 -0
- package/lib/Container/NodePool.js.map +1 -1
- package/lib/Container/Operations.d.ts +2 -2
- package/lib/Container/Operations.d.ts.map +1 -1
- package/lib/Iam/ServiceAccount.d.ts +1 -1
- package/lib/Iam/ServiceAccount.d.ts.map +1 -1
- package/lib/Iam/ServiceAccount.js +21 -2
- package/lib/Iam/ServiceAccount.js.map +1 -1
- package/lib/Iam/ServiceAccountIamMember.d.ts.map +1 -1
- package/lib/Iam/ServiceAccountKey.d.ts +72 -0
- package/lib/Iam/ServiceAccountKey.d.ts.map +1 -0
- package/lib/Iam/ServiceAccountKey.js +164 -0
- package/lib/Iam/ServiceAccountKey.js.map +1 -0
- package/lib/Iam/index.d.ts +2 -0
- package/lib/Iam/index.d.ts.map +1 -1
- package/lib/Iam/index.js +1 -0
- package/lib/Iam/index.js.map +1 -1
- package/lib/Kubernetes/KubernetesManifest.d.ts +1 -1
- package/lib/Kubernetes/Secret.d.ts +1 -1
- package/lib/Kubernetes/client.d.ts.map +1 -1
- package/lib/Kubernetes/connection.d.ts.map +1 -1
- package/lib/ManagedLustre/Instance.d.ts +1 -1
- package/lib/Providers.d.ts +1 -1
- package/lib/Providers.d.ts.map +1 -1
- package/lib/Providers.js +5 -1
- package/lib/Providers.js.map +1 -1
- package/lib/Run/IamMember.d.ts.map +1 -1
- package/lib/Run/IamSync.d.ts.map +1 -1
- package/lib/Run/Job.d.ts +1 -1
- package/lib/Run/Operations.d.ts +2 -2
- package/lib/Run/Operations.d.ts.map +1 -1
- package/lib/Run/Service.d.ts +1 -1
- package/lib/Run/Validation.d.ts.map +1 -1
- package/lib/Sqladmin/Instance.d.ts +1 -1
- package/lib/Sqladmin/Operations.d.ts +2 -2
- package/lib/Sqladmin/Operations.d.ts.map +1 -1
- package/lib/Sqladmin/Types.d.ts.map +1 -1
- package/lib/Sqladmin/Validation.d.ts.map +1 -1
- package/lib/Storage/Bucket.d.ts +117 -0
- package/lib/Storage/Bucket.d.ts.map +1 -0
- package/lib/Storage/Bucket.js +239 -0
- package/lib/Storage/Bucket.js.map +1 -0
- package/lib/Storage/BucketIamMember.d.ts +29 -0
- package/lib/Storage/BucketIamMember.d.ts.map +1 -0
- package/lib/Storage/BucketIamMember.js +26 -0
- package/lib/Storage/BucketIamMember.js.map +1 -0
- package/lib/Storage/index.d.ts +4 -0
- package/lib/Storage/index.d.ts.map +1 -0
- package/lib/Storage/index.js +3 -0
- package/lib/Storage/index.js.map +1 -0
- package/lib/Tags.d.ts.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Container/NodePool.ts +12 -0
- package/src/Iam/ServiceAccount.ts +21 -2
- package/src/Iam/ServiceAccountKey.ts +284 -0
- package/src/Iam/index.ts +5 -0
- package/src/Providers.ts +12 -0
- package/src/Storage/Bucket.ts +439 -0
- package/src/Storage/BucketIamMember.ts +33 -0
- package/src/Storage/index.ts +10 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as iam from "@distilled.cloud/gcp/unstable/iam-v1";
|
|
3
|
+
import { Resource } from "alchemy";
|
|
4
|
+
import { isResolved } from "alchemy/Diff";
|
|
5
|
+
import * as Provider from "alchemy/Provider";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import type * as GCP from "../Providers.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A user-managed service account key (JSON credentials file). Lives
|
|
11
|
+
* under a {@link import("./ServiceAccount.ts").ServiceAccount} and
|
|
12
|
+
* produces a `privateKeyData` field (base64-encoded JSON key file)
|
|
13
|
+
* available ONLY on create — `get`/`list` never return it.
|
|
14
|
+
*
|
|
15
|
+
* The `privateKeyData` attribute is marked stable so the engine
|
|
16
|
+
* preserves it across reconciles (it cannot be re-read from the API).
|
|
17
|
+
* On cold recovery (state loss), if the key exists but
|
|
18
|
+
* `privateKeyData` is absent from state, the old key is deleted and a
|
|
19
|
+
* new one is created so the `privateKeyData` is re-obtained.
|
|
20
|
+
*
|
|
21
|
+
* SA keys carry no labels or description, so adoption cannot be gated
|
|
22
|
+
* by marker — the SA itself is alchemy-owned, and the key is managed
|
|
23
|
+
* exclusively through this resource.
|
|
24
|
+
*
|
|
25
|
+
* @section Creating a ServiceAccountKey
|
|
26
|
+
* @example Mint a JSON key for a GSA
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const key = yield* GCP.ServiceAccountKey("TempBucketKey", {
|
|
29
|
+
* serviceAccount: sa.name, // projects/{p}/serviceAccounts/{email}
|
|
30
|
+
* });
|
|
31
|
+
* // key.privateKeyData is the base64-encoded JSON key file
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export type ServiceAccountKeyProps = {
|
|
35
|
+
/**
|
|
36
|
+
* The resource name of the parent service account, in the format
|
|
37
|
+
* `projects/{PROJECT_ID}/serviceAccounts/{EMAIL_ADDRESS}`.
|
|
38
|
+
* Immutable — changing it triggers a replacement (the key is
|
|
39
|
+
* scoped to the SA).
|
|
40
|
+
*/
|
|
41
|
+
serviceAccount: string;
|
|
42
|
+
/**
|
|
43
|
+
* Key algorithm. Defaults to `KEY_ALG_RSA_2048`. Immutable after
|
|
44
|
+
* create.
|
|
45
|
+
*/
|
|
46
|
+
keyAlgorithm?: "KEY_ALG_RSA_2048" | "KEY_ALG_RSA_1024";
|
|
47
|
+
/**
|
|
48
|
+
* Output format for the private key. Defaults to
|
|
49
|
+
* `TYPE_GOOGLE_CREDENTIALS_FILE` (the Google Credentials JSON
|
|
50
|
+
* format usable by gcloud, gsutil, and the gcsfuse CSI driver).
|
|
51
|
+
*/
|
|
52
|
+
privateKeyType?: "TYPE_GOOGLE_CREDENTIALS_FILE" | "TYPE_PKCS12_FILE";
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type ServiceAccountKey = Resource<
|
|
56
|
+
"GCP.ServiceAccountKey",
|
|
57
|
+
ServiceAccountKeyProps,
|
|
58
|
+
{
|
|
59
|
+
/** Full resource name: `projects/{p}/serviceAccounts/{email}/keys/{keyId}`. */
|
|
60
|
+
name: string;
|
|
61
|
+
/**
|
|
62
|
+
* Base64-encoded private key data (JSON key file). Only available
|
|
63
|
+
* on create — not returned by `get`/`list`. Preserved in alchemy
|
|
64
|
+
* state; on state loss the old key is deleted + a new one is
|
|
65
|
+
* created to re-obtain it.
|
|
66
|
+
*/
|
|
67
|
+
privateKeyData: string | undefined;
|
|
68
|
+
/** Key algorithm used. */
|
|
69
|
+
keyAlgorithm: string | undefined;
|
|
70
|
+
/** Key type: `USER_MANAGED` or `SYSTEM_MANAGED`. */
|
|
71
|
+
keyType: string | undefined;
|
|
72
|
+
/** Key origin: `USER_PROVIDED` or `GOOGLE_PROVIDED`. */
|
|
73
|
+
keyOrigin: string | undefined;
|
|
74
|
+
/** Timestamp after which the key is valid (RFC 3339). */
|
|
75
|
+
validAfterTime: string | undefined;
|
|
76
|
+
/** Whether the key is disabled. */
|
|
77
|
+
disabled: boolean | undefined;
|
|
78
|
+
},
|
|
79
|
+
never,
|
|
80
|
+
GCP.Providers
|
|
81
|
+
>;
|
|
82
|
+
|
|
83
|
+
export const ServiceAccountKey = Resource<ServiceAccountKey>(
|
|
84
|
+
"GCP.ServiceAccountKey",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const toAttributes = (k: iam.ServiceAccountKey): ServiceAccountKey["Attributes"] => ({
|
|
88
|
+
name: k.name ?? "",
|
|
89
|
+
privateKeyData: k.privateKeyData,
|
|
90
|
+
keyAlgorithm: k.keyAlgorithm,
|
|
91
|
+
keyType: k.keyType,
|
|
92
|
+
keyOrigin: k.keyOrigin,
|
|
93
|
+
validAfterTime: k.validAfterTime,
|
|
94
|
+
disabled: k.disabled,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const ServiceAccountKeyProvider = () =>
|
|
98
|
+
Provider.effect(
|
|
99
|
+
ServiceAccountKey,
|
|
100
|
+
Effect.gen(function* () {
|
|
101
|
+
const createProjectsServiceAccountsKeys =
|
|
102
|
+
yield* iam.createProjectsServiceAccountsKeys;
|
|
103
|
+
const deleteProjectsServiceAccountsKeys =
|
|
104
|
+
yield* iam.deleteProjectsServiceAccountsKeys;
|
|
105
|
+
const listProjectsServiceAccountsKeys =
|
|
106
|
+
yield* iam.listProjectsServiceAccountsKeys;
|
|
107
|
+
const getProjectsServiceAccountsKeys =
|
|
108
|
+
yield* iam.getProjectsServiceAccountsKeys;
|
|
109
|
+
|
|
110
|
+
// Find a user-managed key by name (direct probe).
|
|
111
|
+
// NotFound → undefined (key doesn't exist). Forbidden is NOT
|
|
112
|
+
// swallowed — if the caller lacks permission to read this key,
|
|
113
|
+
// propagating the error is safer than treating it as "missing"
|
|
114
|
+
// and potentially creating a duplicate on the SA.
|
|
115
|
+
const observeKey = (keyName: string) =>
|
|
116
|
+
getProjectsServiceAccountsKeys({
|
|
117
|
+
name: keyName,
|
|
118
|
+
publicKeyType: "TYPE_GOOGLE_CREDENTIALS_FILE",
|
|
119
|
+
}).pipe(
|
|
120
|
+
Effect.catchTag("NotFound", () =>
|
|
121
|
+
Effect.succeed(undefined as iam.ServiceAccountKey | undefined),
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// List all user-managed keys for the SA. Used for cold recovery
|
|
126
|
+
// when the key name is not in state. Returns the first
|
|
127
|
+
// user-managed key found (the SA is dedicated to this resource,
|
|
128
|
+
// so there should be at most one user-managed key).
|
|
129
|
+
const findUserManagedKey = Effect.fn(function* (
|
|
130
|
+
serviceAccount: string,
|
|
131
|
+
) {
|
|
132
|
+
const page = yield* listProjectsServiceAccountsKeys({
|
|
133
|
+
name: serviceAccount,
|
|
134
|
+
keyTypes: "USER_MANAGED",
|
|
135
|
+
});
|
|
136
|
+
const keys = page.keys ?? [];
|
|
137
|
+
if (keys.length === 0) return undefined;
|
|
138
|
+
if (keys.length === 1) return keys[0];
|
|
139
|
+
// Multiple user-managed keys — GCP allows multiple keys per
|
|
140
|
+
// SA, so creating another would silently succeed (not
|
|
141
|
+
// Conflict as an earlier comment assumed). Surface an error
|
|
142
|
+
// so the user cleans up the extra keys and re-runs.
|
|
143
|
+
return yield* Effect.fail(
|
|
144
|
+
new ConfigError({
|
|
145
|
+
message:
|
|
146
|
+
`Service account ${serviceAccount} has ${keys.length} user-managed keys; ` +
|
|
147
|
+
`cannot determine which to adopt. Delete the extra keys and re-run.`,
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
// privateKeyData is stable: it's set on create and never
|
|
154
|
+
// changes. The engine preserves it across reconciles and
|
|
155
|
+
// does not use it for drift detection.
|
|
156
|
+
stables: ["name", "privateKeyData", "keyAlgorithm", "keyType"],
|
|
157
|
+
diff: Effect.fn(function* ({ news, olds = {} }) {
|
|
158
|
+
if (!isResolved(news)) return undefined;
|
|
159
|
+
const priorSa = olds.serviceAccount as string | undefined;
|
|
160
|
+
const priorKeyAlgorithm = olds.keyAlgorithm as
|
|
161
|
+
| string
|
|
162
|
+
| undefined;
|
|
163
|
+
const priorPrivateKeyType = olds.privateKeyType as
|
|
164
|
+
| string
|
|
165
|
+
| undefined;
|
|
166
|
+
if (
|
|
167
|
+
(priorSa && news.serviceAccount !== priorSa) ||
|
|
168
|
+
(priorKeyAlgorithm && news.keyAlgorithm !== priorKeyAlgorithm) ||
|
|
169
|
+
(priorPrivateKeyType &&
|
|
170
|
+
news.privateKeyType !== priorPrivateKeyType)
|
|
171
|
+
) {
|
|
172
|
+
return { action: "replace" } as const;
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
}),
|
|
176
|
+
reconcile: Effect.fn(function* ({ id, news, output }) {
|
|
177
|
+
// 1. Observe — check if the key exists by name (from
|
|
178
|
+
// state output). Fall back to listing user-managed
|
|
179
|
+
// keys for cold recovery.
|
|
180
|
+
const keyName = output?.name;
|
|
181
|
+
let observed: iam.ServiceAccountKey | undefined;
|
|
182
|
+
|
|
183
|
+
if (keyName) {
|
|
184
|
+
observed = yield* observeKey(keyName);
|
|
185
|
+
}
|
|
186
|
+
if (!observed) {
|
|
187
|
+
observed = yield* findUserManagedKey(news.serviceAccount);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 2. Ensure — create if missing. If the key exists but
|
|
191
|
+
// privateKeyData is not in state (state loss), delete
|
|
192
|
+
// the old key and create a new one so privateKeyData is
|
|
193
|
+
// re-obtained.
|
|
194
|
+
if (!observed) {
|
|
195
|
+
const created = yield* createProjectsServiceAccountsKeys({
|
|
196
|
+
name: news.serviceAccount,
|
|
197
|
+
body: {
|
|
198
|
+
privateKeyType:
|
|
199
|
+
news.privateKeyType ?? "TYPE_GOOGLE_CREDENTIALS_FILE",
|
|
200
|
+
keyAlgorithm: news.keyAlgorithm ?? "KEY_ALG_RSA_2048",
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
return toAttributes(created);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Key exists. If it is the same key we created before, preserve
|
|
207
|
+
// privateKeyData from state. If the name differs, the key was
|
|
208
|
+
// swapped out-of-band — fall through to delete + recreate so
|
|
209
|
+
// privateKeyData matches the live key.
|
|
210
|
+
if (output?.privateKeyData && observed.name === output.name) {
|
|
211
|
+
return {
|
|
212
|
+
...toAttributes(observed),
|
|
213
|
+
privateKeyData: output.privateKeyData,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// privateKeyData is missing from state. Only delete + recreate
|
|
218
|
+
// when we can PROVE the observed key is ours: output.name must
|
|
219
|
+
// be set and match. SA keys carry no labels, so on cold recovery
|
|
220
|
+
// (output undefined) a found key might be pre-existing or
|
|
221
|
+
// manually rotated — deleting it would destroy someone else's
|
|
222
|
+
// credentials. Fail instead and ask the user to clean up.
|
|
223
|
+
if (output?.name && observed.name === output.name) {
|
|
224
|
+
yield* deleteProjectsServiceAccountsKeys({
|
|
225
|
+
name: observed.name!,
|
|
226
|
+
}).pipe(Effect.catchTag("NotFound", () => Effect.void));
|
|
227
|
+
|
|
228
|
+
const created = yield* createProjectsServiceAccountsKeys({
|
|
229
|
+
name: news.serviceAccount,
|
|
230
|
+
body: {
|
|
231
|
+
privateKeyType:
|
|
232
|
+
news.privateKeyType ?? "TYPE_GOOGLE_CREDENTIALS_FILE",
|
|
233
|
+
keyAlgorithm: news.keyAlgorithm ?? "KEY_ALG_RSA_2048",
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
return toAttributes(created);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Key exists but we can't prove ownership. Don't delete it.
|
|
240
|
+
return yield* Effect.fail(
|
|
241
|
+
new ConfigError({
|
|
242
|
+
message:
|
|
243
|
+
`Service account key ${observed.name} exists on ${news.serviceAccount} ` +
|
|
244
|
+
`but cannot be verified as ours (no matching state). ` +
|
|
245
|
+
`Delete it manually and re-run to create a fresh key.`,
|
|
246
|
+
}),
|
|
247
|
+
);
|
|
248
|
+
}),
|
|
249
|
+
delete: Effect.fn(function* ({ output }) {
|
|
250
|
+
yield* deleteProjectsServiceAccountsKeys({
|
|
251
|
+
name: output.name,
|
|
252
|
+
}).pipe(
|
|
253
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
254
|
+
Effect.catchTag("Forbidden", () => Effect.void),
|
|
255
|
+
);
|
|
256
|
+
}),
|
|
257
|
+
read: Effect.fn(function* ({ id, output, olds }) {
|
|
258
|
+
const keyName = output?.name;
|
|
259
|
+
const serviceAccount = olds.serviceAccount;
|
|
260
|
+
|
|
261
|
+
let observed: iam.ServiceAccountKey | undefined;
|
|
262
|
+
if (keyName) {
|
|
263
|
+
observed = yield* observeKey(keyName);
|
|
264
|
+
}
|
|
265
|
+
if (!observed && serviceAccount) {
|
|
266
|
+
observed = yield* findUserManagedKey(serviceAccount);
|
|
267
|
+
}
|
|
268
|
+
if (!observed) return undefined;
|
|
269
|
+
|
|
270
|
+
// privateKeyData is not available from get/list — preserve it
|
|
271
|
+
// from state output only when it still describes this key.
|
|
272
|
+
const privateKeyData =
|
|
273
|
+
output?.name && observed.name === output.name
|
|
274
|
+
? output.privateKeyData
|
|
275
|
+
: undefined;
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
...toAttributes(observed),
|
|
279
|
+
privateKeyData,
|
|
280
|
+
};
|
|
281
|
+
}),
|
|
282
|
+
};
|
|
283
|
+
}),
|
|
284
|
+
);
|
package/src/Iam/index.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export { ServiceAccount, ServiceAccountProvider } from "./ServiceAccount.ts";
|
|
2
2
|
export type { ServiceAccountProps } from "./ServiceAccount.ts";
|
|
3
3
|
export * from "./ServiceAccountIamMember.ts";
|
|
4
|
+
export {
|
|
5
|
+
ServiceAccountKey,
|
|
6
|
+
ServiceAccountKeyProvider,
|
|
7
|
+
} from "./ServiceAccountKey.ts";
|
|
8
|
+
export type { ServiceAccountKeyProps } from "./ServiceAccountKey.ts";
|
package/src/Providers.ts
CHANGED
|
@@ -27,6 +27,10 @@ import {
|
|
|
27
27
|
ServiceAccount,
|
|
28
28
|
ServiceAccountProvider,
|
|
29
29
|
} from "./Iam/ServiceAccount.ts";
|
|
30
|
+
import {
|
|
31
|
+
ServiceAccountKey,
|
|
32
|
+
ServiceAccountKeyProvider,
|
|
33
|
+
} from "./Iam/ServiceAccountKey.ts";
|
|
30
34
|
import {
|
|
31
35
|
KubernetesManifest,
|
|
32
36
|
KubernetesManifestProvider,
|
|
@@ -45,6 +49,10 @@ import {
|
|
|
45
49
|
PsaConnection,
|
|
46
50
|
PsaConnectionProvider,
|
|
47
51
|
} from "./ServiceNetworking/PsaConnection.ts";
|
|
52
|
+
import {
|
|
53
|
+
StorageBucket,
|
|
54
|
+
StorageBucketProvider,
|
|
55
|
+
} from "./Storage/Bucket.ts";
|
|
48
56
|
import { ApiEnable, ApiEnableProvider } from "./ServiceUsage/ApiEnable.ts";
|
|
49
57
|
import { SqlDatabase, SqlDatabaseProvider } from "./Sqladmin/Database.ts";
|
|
50
58
|
import { SqlInstance, SqlInstanceProvider } from "./Sqladmin/Instance.ts";
|
|
@@ -87,6 +95,7 @@ export const providers = () =>
|
|
|
87
95
|
SharedVpcServiceProject,
|
|
88
96
|
PsaConnection,
|
|
89
97
|
ManagedLustreInstance,
|
|
98
|
+
StorageBucket,
|
|
90
99
|
Service,
|
|
91
100
|
Job,
|
|
92
101
|
SqlInstance,
|
|
@@ -94,6 +103,7 @@ export const providers = () =>
|
|
|
94
103
|
SqlUser,
|
|
95
104
|
ArtifactRegistryRepository,
|
|
96
105
|
ServiceAccount,
|
|
106
|
+
ServiceAccountKey,
|
|
97
107
|
KubernetesSecret,
|
|
98
108
|
KubernetesManifest,
|
|
99
109
|
]),
|
|
@@ -114,6 +124,7 @@ export const providers = () =>
|
|
|
114
124
|
SharedVpcServiceProjectProvider(),
|
|
115
125
|
PsaConnectionProvider(),
|
|
116
126
|
ManagedLustreInstanceProvider(),
|
|
127
|
+
StorageBucketProvider(),
|
|
117
128
|
ServiceProvider(),
|
|
118
129
|
JobProvider(),
|
|
119
130
|
SqlInstanceProvider(),
|
|
@@ -121,6 +132,7 @@ export const providers = () =>
|
|
|
121
132
|
SqlUserProvider(),
|
|
122
133
|
ArtifactRegistryRepositoryProvider(),
|
|
123
134
|
ServiceAccountProvider(),
|
|
135
|
+
ServiceAccountKeyProvider(),
|
|
124
136
|
KubernetesSecretProvider(),
|
|
125
137
|
KubernetesManifestProvider(),
|
|
126
138
|
),
|