@geekmidas/cli 10.0.0-alpha.46 → 10.0.0-alpha.47
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/dist/backends-B9V2XD2M.cjs +82 -0
- package/dist/backends-B9V2XD2M.cjs.map +1 -0
- package/dist/backends-CSuLl0YP.mjs +59 -0
- package/dist/backends-CSuLl0YP.mjs.map +1 -0
- package/dist/encryption-C7OGMve_.cjs +91 -0
- package/dist/encryption-C7OGMve_.cjs.map +1 -0
- package/dist/encryption-DyQnPsZN.mjs +90 -0
- package/dist/encryption-DyQnPsZN.mjs.map +1 -0
- package/dist/index.cjs +87 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +79 -40
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-Dp5HFzuQ.cjs → migrate-BgEY9pdP.cjs} +2 -2
- package/dist/{migrate-Dp5HFzuQ.cjs.map → migrate-BgEY9pdP.cjs.map} +1 -1
- package/dist/{migrate-B3opyC3o.mjs → migrate-DhxTIA0z.mjs} +2 -2
- package/dist/{migrate-B3opyC3o.mjs.map → migrate-DhxTIA0z.mjs.map} +1 -1
- package/dist/{ready-V6Ou6-B6.mjs → ready-WfT-eWlm.mjs} +2 -1
- package/dist/{ready-V6Ou6-B6.mjs.map → ready-WfT-eWlm.mjs.map} +1 -1
- package/dist/{ready-L7I68yXf.cjs → ready-lr2Fm-ep.cjs} +2 -1
- package/dist/{ready-L7I68yXf.cjs.map → ready-lr2Fm-ep.cjs.map} +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/{workspace-CHEC80sp.mjs → workspace-cb6U29EL.mjs} +56 -77
- package/dist/workspace-cb6U29EL.mjs.map +1 -0
- package/dist/{workspace-D9z2ymBW.cjs → workspace-vafrzZTC.cjs} +60 -99
- package/dist/workspace-vafrzZTC.cjs.map +1 -0
- package/package.json +14 -14
- package/dist/workspace-CHEC80sp.mjs.map +0 -1
- package/dist/workspace-D9z2ymBW.cjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -5,10 +5,11 @@ import { d as parseModuleConfig, f as appKey, l as loadWorkspaceConfig, n as Not
|
|
|
5
5
|
import { D as assertDeployedStage, E as TEST_STAGE, O as deployedProblems, T as InvalidStages, a as getAppBuildOrder, b as getDeployTargetError, k as stageProblems, m as stripPublicPrefix, o as getAppGkmConfig, p as getPublicEnvPrefix, t as allConstructGlobs, x as isDeployTargetSupported } from "./workspace-DNzWgM1J.mjs";
|
|
6
6
|
import { a as withCustomSecret, i as toEmbeddableSecrets, n as maskPassword, t as initStageSecrets } from "./storage-BzaUxmqe.mjs";
|
|
7
7
|
import { a as getKeyPath, i as FileSecretsStore, n as secretsStoreFor } from "./store-DeGATCS-.mjs";
|
|
8
|
-
import { C as
|
|
8
|
+
import { C as loadEnvFiles, S as isPortAvailable, T as prepareEntryCredentials, _ as fakeKey, a as reconcileWorkspace, b as createEntryWrapper, c as LOCAL_CA_PATH, d as postgresDatabaseNames, f as quoteIdentifier, g as describeServices, h as rootSite, i as derivedContainers, l as forgetState, m as resourceName, n as backendsOf$1, p as pgClient, r as constructGlobs, s as COMPOSE_PATH, t as FAKE_ENV, u as applyPostgres, v as primaryPortKey, w as loadSecretsForApp, x as findAvailablePort, y as createCredentialsPreload } from "./workspace-cb6U29EL.mjs";
|
|
9
9
|
import { n as EndpointGenerator, r as runtimeFor } from "./OpenApiTsGenerator-BzIGy8KE.mjs";
|
|
10
10
|
import { generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi.mjs";
|
|
11
|
-
import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-
|
|
11
|
+
import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-WfT-eWlm.mjs";
|
|
12
|
+
import { i as storageBackendFor, n as eventsBackendFor, r as providerOf, t as cacheBackendFor } from "./backends-CSuLl0YP.mjs";
|
|
12
13
|
import { n as withCompute, r as withRoutes, t as manifestModule } from "./emit-C1e8qD08.mjs";
|
|
13
14
|
import { createRequire } from "node:module";
|
|
14
15
|
import { Command } from "commander";
|
|
@@ -24,6 +25,7 @@ import fg from "fast-glob";
|
|
|
24
25
|
import chokidar from "chokidar";
|
|
25
26
|
import { createCipheriv, createHash, randomBytes } from "node:crypto";
|
|
26
27
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
28
|
+
import { generateKeyring } from "@geekmidas/constructs/encryption";
|
|
27
29
|
import { ownerRole, readerRole, roleStatements } from "@geekmidas/db/pg/roles";
|
|
28
30
|
import { Client } from "pg";
|
|
29
31
|
import { parse as parse$1, parseDocument } from "yaml";
|
|
@@ -40,7 +42,7 @@ import { Queue } from "@geekmidas/constructs/queue";
|
|
|
40
42
|
import { Topic } from "@geekmidas/constructs/topic";
|
|
41
43
|
import { lookup } from "node:dns/promises";
|
|
42
44
|
//#region package.json
|
|
43
|
-
var version = "10.0.0-alpha.
|
|
45
|
+
var version = "10.0.0-alpha.47";
|
|
44
46
|
//#endregion
|
|
45
47
|
//#region src/auth/credentials.ts
|
|
46
48
|
/**
|
|
@@ -1196,9 +1198,9 @@ async function devCommand(options) {
|
|
|
1196
1198
|
stage: workspace.stages.local,
|
|
1197
1199
|
...options.fake ? { fake: true } : {}
|
|
1198
1200
|
});
|
|
1199
|
-
if (reconciled.
|
|
1200
|
-
logger$9.log(
|
|
1201
|
-
for (const
|
|
1201
|
+
if (reconciled.services.length > 0) {
|
|
1202
|
+
logger$9.log("🐳 Services");
|
|
1203
|
+
for (const line of describeServices(reconciled.services)) logger$9.log(line);
|
|
1202
1204
|
}
|
|
1203
1205
|
Object.assign(appSecrets, reconciled.env);
|
|
1204
1206
|
const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && appKey(r.id) === workspaceAppName);
|
|
@@ -1479,9 +1481,9 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1479
1481
|
stage: workspace.stages.local,
|
|
1480
1482
|
...options.fake ? { fake: true } : {}
|
|
1481
1483
|
});
|
|
1482
|
-
if (reconciled.
|
|
1483
|
-
logger$9.log(
|
|
1484
|
-
for (const
|
|
1484
|
+
if (reconciled.services.length > 0) {
|
|
1485
|
+
logger$9.log("🐳 Services");
|
|
1486
|
+
for (const line of describeServices(reconciled.services)) logger$9.log(line);
|
|
1485
1487
|
}
|
|
1486
1488
|
const secretsEnv = {
|
|
1487
1489
|
...rawSecrets,
|
|
@@ -1490,9 +1492,9 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1490
1492
|
const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
|
|
1491
1493
|
for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
|
|
1492
1494
|
if (options.migrate || options.seed) {
|
|
1493
|
-
const { prepareDevDatabases } = await import("./migrate-
|
|
1495
|
+
const { prepareDevDatabases } = await import("./migrate-DhxTIA0z.mjs");
|
|
1494
1496
|
await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
|
|
1495
|
-
} else await import("./migrate-
|
|
1497
|
+
} else await import("./migrate-DhxTIA0z.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
|
|
1496
1498
|
logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
|
|
1497
1499
|
});
|
|
1498
1500
|
const appUrls = {};
|
|
@@ -3370,6 +3372,19 @@ const PROVISIONERS = {
|
|
|
3370
3372
|
return { provides: { [key]: supplied(declaration.id, key, context) } };
|
|
3371
3373
|
},
|
|
3372
3374
|
/**
|
|
3375
|
+
* The keyring the stage keeps in its secrets.
|
|
3376
|
+
*
|
|
3377
|
+
* Generated on the first deploy (`withGeneratedSecrets`) and rotated only
|
|
3378
|
+
* by `gkm encryption:rotate`, so a redeploy never changes a key and nothing
|
|
3379
|
+
* written becomes unreadable. Nothing is created in Dokploy: the process
|
|
3380
|
+
* holds the keyring.
|
|
3381
|
+
*/
|
|
3382
|
+
encryption: async (declaration, context) => {
|
|
3383
|
+
if (declaration.kind !== "encryption") throw new WrongKind(declaration.kind);
|
|
3384
|
+
const key = provideKey(declaration.id, "url");
|
|
3385
|
+
return { provides: { [key]: supplied(declaration.id, key, context) } };
|
|
3386
|
+
},
|
|
3387
|
+
/**
|
|
3373
3388
|
* A third party's credentials, as the stage was given them.
|
|
3374
3389
|
*
|
|
3375
3390
|
* Nothing is created and nothing derived: the value was issued by somebody
|
|
@@ -6373,6 +6388,8 @@ function validateEnvVars(requiredVars, context) {
|
|
|
6373
6388
|
* who could read the repo.
|
|
6374
6389
|
* - **Each `secret` construct's value** — an auth server's signing secret —
|
|
6375
6390
|
* random, rather than derived.
|
|
6391
|
+
* - **Each `encryption` construct's keyring** — one random key and an index
|
|
6392
|
+
* key. Later keys are added by `gkm encryption:rotate`, never by a deploy.
|
|
6376
6393
|
*
|
|
6377
6394
|
* Both are generated on the first deploy that needs them and written to the
|
|
6378
6395
|
* stage's store, so every later deploy reads the same values: sessions survive
|
|
@@ -6388,10 +6405,10 @@ function withGeneratedSecrets(secrets, manifest) {
|
|
|
6388
6405
|
const generated = [];
|
|
6389
6406
|
const custom = { ...secrets.custom };
|
|
6390
6407
|
for (const declaration of Object.values(manifest)) {
|
|
6391
|
-
if (declaration?.kind !== "secret") continue;
|
|
6408
|
+
if (declaration?.kind !== "secret" && declaration?.kind !== "encryption") continue;
|
|
6392
6409
|
const key = declaration.provides?.[0];
|
|
6393
6410
|
if (!key || custom[key]) continue;
|
|
6394
|
-
custom[key] = random();
|
|
6411
|
+
custom[key] = declaration.kind === "encryption" ? generateKeyring() : random();
|
|
6395
6412
|
generated.push(key);
|
|
6396
6413
|
}
|
|
6397
6414
|
const seed = secrets.seed ?? random();
|
|
@@ -9065,26 +9082,26 @@ function loadPackageJson() {
|
|
|
9065
9082
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
9066
9083
|
*/
|
|
9067
9084
|
const GEEKMIDAS_VERSIONS = {
|
|
9068
|
-
"@geekmidas/audit": "~10.0.0-alpha.
|
|
9069
|
-
"@geekmidas/auth": "~10.0.0-alpha.
|
|
9070
|
-
"@geekmidas/cache": "~10.0.0-alpha.
|
|
9071
|
-
"@geekmidas/client": "~10.0.0-alpha.
|
|
9072
|
-
"@geekmidas/cloud": "~10.0.0-alpha.
|
|
9073
|
-
"@geekmidas/constructs": "~10.0.0-alpha.
|
|
9074
|
-
"@geekmidas/db": "~10.0.0-alpha.
|
|
9075
|
-
"@geekmidas/emailkit": "~10.0.0-alpha.
|
|
9076
|
-
"@geekmidas/envkit": "~10.0.0-alpha.
|
|
9077
|
-
"@geekmidas/errors": "~10.0.0-alpha.
|
|
9078
|
-
"@geekmidas/events": "~10.0.0-alpha.
|
|
9079
|
-
"@geekmidas/logger": "~10.0.0-alpha.
|
|
9080
|
-
"@geekmidas/manifest": "~10.0.0-alpha.
|
|
9081
|
-
"@geekmidas/rate-limit": "~10.0.0-alpha.
|
|
9082
|
-
"@geekmidas/schema": "~10.0.0-alpha.
|
|
9083
|
-
"@geekmidas/services": "~10.0.0-alpha.
|
|
9084
|
-
"@geekmidas/storage": "~10.0.0-alpha.
|
|
9085
|
-
"@geekmidas/studio": "~10.0.0-alpha.
|
|
9086
|
-
"@geekmidas/telescope": "~10.0.0-alpha.
|
|
9087
|
-
"@geekmidas/testkit": "~10.0.0-alpha.
|
|
9085
|
+
"@geekmidas/audit": "~10.0.0-alpha.47",
|
|
9086
|
+
"@geekmidas/auth": "~10.0.0-alpha.47",
|
|
9087
|
+
"@geekmidas/cache": "~10.0.0-alpha.47",
|
|
9088
|
+
"@geekmidas/client": "~10.0.0-alpha.47",
|
|
9089
|
+
"@geekmidas/cloud": "~10.0.0-alpha.47",
|
|
9090
|
+
"@geekmidas/constructs": "~10.0.0-alpha.47",
|
|
9091
|
+
"@geekmidas/db": "~10.0.0-alpha.47",
|
|
9092
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.47",
|
|
9093
|
+
"@geekmidas/envkit": "~10.0.0-alpha.47",
|
|
9094
|
+
"@geekmidas/errors": "~10.0.0-alpha.47",
|
|
9095
|
+
"@geekmidas/events": "~10.0.0-alpha.47",
|
|
9096
|
+
"@geekmidas/logger": "~10.0.0-alpha.47",
|
|
9097
|
+
"@geekmidas/manifest": "~10.0.0-alpha.47",
|
|
9098
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.47",
|
|
9099
|
+
"@geekmidas/schema": "~10.0.0-alpha.47",
|
|
9100
|
+
"@geekmidas/services": "~10.0.0-alpha.47",
|
|
9101
|
+
"@geekmidas/storage": "~10.0.0-alpha.47",
|
|
9102
|
+
"@geekmidas/studio": "~10.0.0-alpha.47",
|
|
9103
|
+
"@geekmidas/telescope": "~10.0.0-alpha.47",
|
|
9104
|
+
"@geekmidas/testkit": "~10.0.0-alpha.47",
|
|
9088
9105
|
"@geekmidas/cli": `~${loadPackageJson().version}`
|
|
9089
9106
|
};
|
|
9090
9107
|
//#endregion
|
|
@@ -15493,8 +15510,8 @@ async function reconcileLocal(workspace, stage, options) {
|
|
|
15493
15510
|
logger$1.log("🐳 Services already up to date");
|
|
15494
15511
|
return;
|
|
15495
15512
|
}
|
|
15496
|
-
logger$1.log(
|
|
15497
|
-
for (const
|
|
15513
|
+
logger$1.log("🐳 Services");
|
|
15514
|
+
for (const line of describeServices(result.services)) logger$1.log(line);
|
|
15498
15515
|
const url = result.plan.resources.filter((r) => r.kind === "rest-api" || r.kind === "site" || r.kind === "file-server").map((r) => result.env[r.envKey]).find((address) => address?.startsWith("https://"));
|
|
15499
15516
|
if (url) await ensureTrusted(workspace.root, url, { ...options.yes ? { assumeYes: true } : {} });
|
|
15500
15517
|
}
|
|
@@ -15841,7 +15858,7 @@ function testDatabases(reconciled) {
|
|
|
15841
15858
|
* starts without the reference data the app needs.
|
|
15842
15859
|
*/
|
|
15843
15860
|
async function migrateTestStage(workspace, env) {
|
|
15844
|
-
const { migrateAndSeed } = await import("./migrate-
|
|
15861
|
+
const { migrateAndSeed } = await import("./migrate-DhxTIA0z.mjs");
|
|
15845
15862
|
const { discover } = await import("./discover-Cf2jAcgF.mjs").then((n) => n.n);
|
|
15846
15863
|
const sources = {};
|
|
15847
15864
|
const manifest = await discover({
|
|
@@ -16272,7 +16289,7 @@ program.command("migrate").description("Apply each database construct's migratio
|
|
|
16272
16289
|
try {
|
|
16273
16290
|
const globalOptions = program.opts();
|
|
16274
16291
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16275
|
-
const { migrateCommand } = await import("./migrate-
|
|
16292
|
+
const { migrateCommand } = await import("./migrate-DhxTIA0z.mjs");
|
|
16276
16293
|
await migrateCommand({
|
|
16277
16294
|
...options,
|
|
16278
16295
|
...construct ? { construct } : {}
|
|
@@ -16286,7 +16303,7 @@ program.command("seed").description("Migrate, then run each database construct's
|
|
|
16286
16303
|
try {
|
|
16287
16304
|
const globalOptions = program.opts();
|
|
16288
16305
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16289
|
-
const { seedCommand } = await import("./migrate-
|
|
16306
|
+
const { seedCommand } = await import("./migrate-DhxTIA0z.mjs");
|
|
16290
16307
|
await seedCommand({
|
|
16291
16308
|
...options,
|
|
16292
16309
|
...construct ? { construct } : {}
|
|
@@ -16300,7 +16317,7 @@ program.command("migration").description("Write a construct's next migration: an
|
|
|
16300
16317
|
try {
|
|
16301
16318
|
const globalOptions = program.opts();
|
|
16302
16319
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16303
|
-
const { migrationCommand } = await import("./migrate-
|
|
16320
|
+
const { migrationCommand } = await import("./migrate-DhxTIA0z.mjs");
|
|
16304
16321
|
await migrationCommand({
|
|
16305
16322
|
construct,
|
|
16306
16323
|
...name ? { name } : {}
|
|
@@ -16394,6 +16411,28 @@ program.command("secrets:set").description("Set a custom secret for a stage").ar
|
|
|
16394
16411
|
process.exit(1);
|
|
16395
16412
|
}
|
|
16396
16413
|
});
|
|
16414
|
+
program.command("encryption:rotate").description("Add a new current key to an Encryption construct's keyring on a server stage").argument("<construct>", "The Encryption construct (e.g. Pii)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, options) => {
|
|
16415
|
+
try {
|
|
16416
|
+
const globalOptions = program.opts();
|
|
16417
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16418
|
+
const { encryptionRotateCommand } = await import("./encryption-DyQnPsZN.mjs");
|
|
16419
|
+
await encryptionRotateCommand(construct, options);
|
|
16420
|
+
} catch (error) {
|
|
16421
|
+
console.error(formatError(error));
|
|
16422
|
+
process.exit(1);
|
|
16423
|
+
}
|
|
16424
|
+
});
|
|
16425
|
+
program.command("encryption:retire").description("Remove an old key from an Encryption construct's keyring, once nothing is under it").argument("<construct>", "The Encryption construct (e.g. Pii)").argument("<key>", "The key to retire (e.g. k1)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, key, options) => {
|
|
16426
|
+
try {
|
|
16427
|
+
const globalOptions = program.opts();
|
|
16428
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16429
|
+
const { encryptionRetireCommand } = await import("./encryption-DyQnPsZN.mjs");
|
|
16430
|
+
await encryptionRetireCommand(construct, key, options);
|
|
16431
|
+
} catch (error) {
|
|
16432
|
+
console.error(formatError(error));
|
|
16433
|
+
process.exit(1);
|
|
16434
|
+
}
|
|
16435
|
+
});
|
|
16397
16436
|
program.command("secrets:show").description("Show secrets for a stage").requiredOption("--stage <stage>", "Stage name").option("--reveal", "Show actual secret values (not masked)").action(async (options) => {
|
|
16398
16437
|
try {
|
|
16399
16438
|
const globalOptions = program.opts();
|
|
@@ -16439,7 +16478,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
16439
16478
|
console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
16440
16479
|
process.exit(1);
|
|
16441
16480
|
}
|
|
16442
|
-
const { derivedContainers } = await import("./workspace-
|
|
16481
|
+
const { derivedContainers } = await import("./workspace-cb6U29EL.mjs").then((n) => n.o);
|
|
16443
16482
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
|
|
16444
16483
|
if (!result) {
|
|
16445
16484
|
console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
|