@geekmidas/cli 10.0.0-alpha.69 → 10.0.0-alpha.71
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/{LegacyStateStore-LS_uTO8D.cjs → LegacyStateStore-Dd5IwiyC.cjs} +2 -2
- package/dist/{LegacyStateStore-LS_uTO8D.cjs.map → LegacyStateStore-Dd5IwiyC.cjs.map} +1 -1
- package/dist/{LegacyStateStore-BE1Et8RS.mjs → LegacyStateStore-NSHEinQi.mjs} +2 -2
- package/dist/{LegacyStateStore-BE1Et8RS.mjs.map → LegacyStateStore-NSHEinQi.mjs.map} +1 -1
- package/dist/{LocalStateStore-CV6phNMZ.cjs → LocalStateStore-DTylG4T4.cjs} +2 -2
- package/dist/{LocalStateStore-CV6phNMZ.cjs.map → LocalStateStore-DTylG4T4.cjs.map} +1 -1
- package/dist/{LocalStateStore-DAnFc708.mjs → LocalStateStore-DUoG2wA_.mjs} +2 -2
- package/dist/{LocalStateStore-DAnFc708.mjs.map → LocalStateStore-DUoG2wA_.mjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-CSaXs-dB.mjs → OpenApiTsGenerator-Bhr_XWWN.mjs} +57 -638
- package/dist/OpenApiTsGenerator-Bhr_XWWN.mjs.map +1 -0
- package/dist/{OpenApiTsGenerator-CxB8mqXz.cjs → OpenApiTsGenerator-DZZwHdDC.cjs} +57 -638
- package/dist/OpenApiTsGenerator-DZZwHdDC.cjs.map +1 -0
- package/dist/{S3StateStore-dA34LAYm.cjs → S3StateStore-D7hrU-sy.cjs} +2 -2
- package/dist/{S3StateStore-dA34LAYm.cjs.map → S3StateStore-D7hrU-sy.cjs.map} +1 -1
- package/dist/{S3StateStore-8kJEGnTh.mjs → S3StateStore-Dxob3PNA.mjs} +2 -2
- package/dist/{S3StateStore-8kJEGnTh.mjs.map → S3StateStore-Dxob3PNA.mjs.map} +1 -1
- package/dist/{SSMStateStore-DBzlfc-S.cjs → SSMStateStore-DGIKJ4NN.cjs} +2 -2
- package/dist/{SSMStateStore-DBzlfc-S.cjs.map → SSMStateStore-DGIKJ4NN.cjs.map} +1 -1
- package/dist/{SSMStateStore-Dkdw-fPL.mjs → SSMStateStore-Dvl4A8Up.mjs} +2 -2
- package/dist/{SSMStateStore-Dkdw-fPL.mjs.map → SSMStateStore-Dvl4A8Up.mjs.map} +1 -1
- package/dist/{add-CoIr2wgv.cjs → add-DeC2Kyyv.cjs} +3 -3
- package/dist/{add-CoIr2wgv.cjs.map → add-DeC2Kyyv.cjs.map} +1 -1
- package/dist/{add-Dzk23476.mjs → add-XTLU19_E.mjs} +3 -3
- package/dist/{add-Dzk23476.mjs.map → add-XTLU19_E.mjs.map} +1 -1
- package/dist/{bundler-CSR2nM4m.cjs → bundler-CEaR6Dpb.cjs} +6 -6
- package/dist/bundler-CEaR6Dpb.cjs.map +1 -0
- package/dist/{bundler-Cn0JF5G0.mjs → bundler-CNTVLCCA.mjs} +6 -6
- package/dist/bundler-CNTVLCCA.mjs.map +1 -0
- package/dist/{cli-ij8Lwlww.mjs → cli-D1arS0p1.mjs} +3 -3
- package/dist/{cli-ij8Lwlww.mjs.map → cli-D1arS0p1.mjs.map} +1 -1
- package/dist/{cli-IoM2-x48.cjs → cli-MMgBrHx7.cjs} +3 -3
- package/dist/{cli-IoM2-x48.cjs.map → cli-MMgBrHx7.cjs.map} +1 -1
- package/dist/{compose-DfIioFX0.cjs → compose-B-MME-4C.cjs} +358 -16
- package/dist/compose-B-MME-4C.cjs.map +1 -0
- package/dist/{compose-CZtinmtw.mjs → compose-T3hnnjKZ.mjs} +353 -17
- package/dist/compose-T3hnnjKZ.mjs.map +1 -0
- package/dist/{config-CxEp_g7j.d.mts → config-BN6iXvyR.d.mts} +3 -3
- package/dist/{config-BnA0kPTY.d.cts.map → config-BN6iXvyR.d.mts.map} +1 -1
- package/dist/{config-BnA0kPTY.d.cts → config-j9zBKaEG.d.cts} +3 -3
- package/dist/{config-CxEp_g7j.d.mts.map → config-j9zBKaEG.d.cts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/deploy/public.cjs +6 -6
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-Dpz9raPM.cjs → deploy-CZE0m6jd.cjs} +5 -5
- package/dist/{deploy-Dpz9raPM.cjs.map → deploy-CZE0m6jd.cjs.map} +1 -1
- package/dist/{deploy-BzqbkJ3o.mjs → deploy-ClC53rc6.mjs} +5 -5
- package/dist/{deploy-BzqbkJ3o.mjs.map → deploy-ClC53rc6.mjs.map} +1 -1
- package/dist/{dokploy-DkwcORbv.mjs → dokploy-D1UwQKm3.mjs} +2 -2
- package/dist/{dokploy-DkwcORbv.mjs.map → dokploy-D1UwQKm3.mjs.map} +1 -1
- package/dist/{dokploy-B6O-J1fb.cjs → dokploy-lwmH05zr.cjs} +2 -2
- package/dist/{dokploy-B6O-J1fb.cjs.map → dokploy-lwmH05zr.cjs.map} +1 -1
- package/dist/{encryption-C8Ic5t0C.cjs → encryption-D05sNwED.cjs} +3 -3
- package/dist/{encryption-C8Ic5t0C.cjs.map → encryption-D05sNwED.cjs.map} +1 -1
- package/dist/{encryption-7m1mKcRy.mjs → encryption-DcrxWl1s.mjs} +3 -3
- package/dist/{encryption-7m1mKcRy.mjs.map → encryption-DcrxWl1s.mjs.map} +1 -1
- package/dist/{engine-BR9qlS7A.cjs → engine-Cry1vwMz.cjs} +6 -5
- package/dist/engine-Cry1vwMz.cjs.map +1 -0
- package/dist/{engine-62Kl70Pj.mjs → engine-DmQS3XHX.mjs} +6 -5
- package/dist/{engine-62Kl70Pj.mjs.map → engine-DmQS3XHX.mjs.map} +1 -1
- package/dist/{github-CmGIZjhu.cjs → github-BchWoiVx.cjs} +3 -3
- package/dist/{github-CmGIZjhu.cjs.map → github-BchWoiVx.cjs.map} +1 -1
- package/dist/{github-DtymyOcH.mjs → github-CqYOP8cI.mjs} +3 -3
- package/dist/{github-DtymyOcH.mjs.map → github-CqYOP8cI.mjs.map} +1 -1
- package/dist/{index-CkX89m6S.d.mts → index-Bk3NY6DN.d.cts} +2 -2
- package/dist/{index-CkX89m6S.d.mts.map → index-Bk3NY6DN.d.cts.map} +1 -1
- package/dist/{index-EvZBkycu.d.cts → index-DvoxuTqR.d.mts} +2 -2
- package/dist/{index-EvZBkycu.d.cts.map → index-DvoxuTqR.d.mts.map} +1 -1
- package/dist/index.cjs +53 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +53 -52
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-CEzq6DjL.mjs → migrate-guck0NJK.mjs} +3 -3
- package/dist/{migrate-CEzq6DjL.mjs.map → migrate-guck0NJK.mjs.map} +1 -1
- package/dist/{migrate-CYC-hBOU.cjs → migrate-qKeGYq21.cjs} +3 -3
- package/dist/{migrate-CYC-hBOU.cjs.map → migrate-qKeGYq21.cjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/{ready-QGgjmcuN.cjs → ready-Dp6arkI4.cjs} +5 -5
- package/dist/ready-Dp6arkI4.cjs.map +1 -0
- package/dist/{ready-DeYaSoNN.mjs → ready-xpoX11uu.mjs} +5 -5
- package/dist/ready-xpoX11uu.mjs.map +1 -0
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-Dn5wGf1r.mjs → resolve-BsXEXAUz.mjs} +3 -3
- package/dist/{resolve-Dn5wGf1r.mjs.map → resolve-BsXEXAUz.mjs.map} +1 -1
- package/dist/{resolve-BDsMffvz.cjs → resolve-wEjEvbJ5.cjs} +3 -3
- package/dist/{resolve-BDsMffvz.cjs.map → resolve-wEjEvbJ5.cjs.map} +1 -1
- package/dist/{rollback-DDfaqv7P.mjs → rollback-Bk91csFg.mjs} +5 -5
- package/dist/{rollback-DDfaqv7P.mjs.map → rollback-Bk91csFg.mjs.map} +1 -1
- package/dist/{rollback-5XHaBDxW.cjs → rollback-DmcU-efZ.cjs} +5 -5
- package/dist/{rollback-5XHaBDxW.cjs.map → rollback-DmcU-efZ.cjs.map} +1 -1
- package/dist/{runtime-B3jNgeP-.d.mts → runtime-CYAO4iZG.d.cts} +2 -2
- package/dist/{runtime-B3jNgeP-.d.mts.map → runtime-CYAO4iZG.d.cts.map} +1 -1
- package/dist/{runtime-DWThEP-r.d.cts → runtime-DHJhe4QI.d.mts} +2 -2
- package/dist/{runtime-DWThEP-r.d.cts.map → runtime-DHJhe4QI.d.mts.map} +1 -1
- package/dist/{sniffer-Bc0nNBDF.cjs → sniffer-DpHpFZBD.cjs} +6 -6
- package/dist/sniffer-DpHpFZBD.cjs.map +1 -0
- package/dist/{sniffer-DMqi2b1q.mjs → sniffer-vAXsU_4G.mjs} +6 -6
- package/dist/sniffer-vAXsU_4G.mjs.map +1 -0
- package/dist/{state-DClnPZt5.mjs → state-BJFherj1.mjs} +60 -5
- package/dist/state-BJFherj1.mjs.map +1 -0
- package/dist/{state-8RgXeX5Y.cjs → state-CCuTJNRH.cjs} +71 -4
- package/dist/state-CCuTJNRH.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-CZdCxUCK.d.cts → types-BD1jgA85.d.cts} +70 -2
- package/dist/types-BD1jgA85.d.cts.map +1 -0
- package/dist/{types-Da0E3Qv7.d.mts → types-DkG5WW8l.d.mts} +70 -2
- package/dist/types-DkG5WW8l.d.mts.map +1 -0
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-B2UK_rVP.mjs → workspace-C7NqCsQF.mjs} +104 -2
- package/dist/workspace-C7NqCsQF.mjs.map +1 -0
- package/dist/{workspace-8NuAjaXJ.cjs → workspace-vdrcRI-m.cjs} +115 -1
- package/dist/workspace-vdrcRI-m.cjs.map +1 -0
- package/package.json +15 -15
- package/dist/OpenApiTsGenerator-CSaXs-dB.mjs.map +0 -1
- package/dist/OpenApiTsGenerator-CxB8mqXz.cjs.map +0 -1
- package/dist/bundler-CSR2nM4m.cjs.map +0 -1
- package/dist/bundler-Cn0JF5G0.mjs.map +0 -1
- package/dist/compose-CZtinmtw.mjs.map +0 -1
- package/dist/compose-DfIioFX0.cjs.map +0 -1
- package/dist/engine-BR9qlS7A.cjs.map +0 -1
- package/dist/ready-DeYaSoNN.mjs.map +0 -1
- package/dist/ready-QGgjmcuN.cjs.map +0 -1
- package/dist/sniffer-Bc0nNBDF.cjs.map +0 -1
- package/dist/sniffer-DMqi2b1q.mjs.map +0 -1
- package/dist/state-8RgXeX5Y.cjs.map +0 -1
- package/dist/state-DClnPZt5.mjs.map +0 -1
- package/dist/types-CZdCxUCK.d.cts.map +0 -1
- package/dist/types-Da0E3Qv7.d.mts.map +0 -1
- package/dist/workspace-8NuAjaXJ.cjs.map +0 -1
- package/dist/workspace-B2UK_rVP.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const require_workspace = require("./workspace-
|
|
1
|
+
const require_workspace = require("./workspace-vdrcRI-m.cjs");
|
|
2
2
|
const require_config = require("./config.cjs");
|
|
3
|
-
const require_state = require("./state-
|
|
3
|
+
const require_state = require("./state-CCuTJNRH.cjs");
|
|
4
4
|
let node_child_process = require("node:child_process");
|
|
5
5
|
let _aws_sdk_client_iam = require("@aws-sdk/client-iam");
|
|
6
6
|
//#region src/deploy/github.ts
|
|
@@ -210,4 +210,4 @@ var SsoSessionExpired = class extends Error {
|
|
|
210
210
|
//#endregion
|
|
211
211
|
exports.deployGithubCommand = deployGithubCommand;
|
|
212
212
|
|
|
213
|
-
//# sourceMappingURL=github-
|
|
213
|
+
//# sourceMappingURL=github-BchWoiVx.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-CmGIZjhu.cjs","names":["execFileSync","ListOpenIDConnectProvidersCommand","CreateOpenIDConnectProviderCommand","GetRoleCommand","UpdateAssumeRolePolicyCommand","CreateRoleCommand","AttachRolePolicyCommand","IAMClient","loadWorkspaceConfig","readKey","keystoreProject","getKeyPath","isRemoteStore","secretsStoreFor"],"sources":["../src/deploy/github.ts"],"sourcesContent":["/**\n * `gkm deploy:github` — let GitHub Actions deploy one stage, with no keys.\n *\n * A stage usually lives in its own AWS account — staging in one, production in\n * another — so this runs once per stage, with that account's profile:\n *\n * gkm deploy:github --stage staging --profile acme-dev\n * gkm deploy:github --stage prod --profile acme-prod\n *\n * In the stage's account it makes sure GitHub's OIDC provider exists, and a\n * role that only this repository's `<stage>` environment can assume. On\n * GitHub it creates that environment and gives it what the generated deploy\n * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in\n * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to\n * SSM the deploy job pulls them with the role instead, so no key is handed to\n * GitHub, and this pushes the stage's local secrets to SSM in the same account,\n * with the same profile. Re-running it converges rather than duplicating.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n\tAttachRolePolicyCommand,\n\tCreateOpenIDConnectProviderCommand,\n\tCreateRoleCommand,\n\tGetRoleCommand,\n\tIAMClient,\n\ttype IAMClientConfig,\n\tListOpenIDConnectProvidersCommand,\n\tUpdateAssumeRolePolicyCommand,\n} from '@aws-sdk/client-iam';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { getKeyPath, keystoreProject, readKey } from '../secrets/keystore.js';\nimport { isRemoteStore, secretsStoreFor } from '../secrets/store.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\n\nconst logger = console;\n\nconst GITHUB_OIDC_HOST = 'token.actions.githubusercontent.com';\nconst AUDIENCE = 'sts.amazonaws.com';\n\n/**\n * What SST needs to create a stack is most of AWS, so this is the default —\n * said out loud in the output, and replaceable with `--policy-arn`.\n */\nexport const DEFAULT_POLICY_ARN = 'arn:aws:iam::aws:policy/AdministratorAccess';\n\nexport interface DeployGithubOptions {\n\tstage: string;\n\t/** The AWS profile for the stage's account. */\n\tprofile?: string;\n\t/** `owner/name`; defaults to the repository `gh` sees here. */\n\trepo?: string;\n\t/** The policy the deploy role gets. */\n\tpolicyArn?: string;\n\tdryRun?: boolean;\n}\n\n/** Runs `gh` with the given arguments and optional stdin, returning stdout. */\nexport type Gh = (args: string[], input?: string) => string;\n\nconst defaultGh: Gh = (args, input) =>\n\texecFileSync('gh', args, {\n\t\tencoding: 'utf-8',\n\t\t...(input === undefined\n\t\t\t? {}\n\t\t\t: { input, stdio: ['pipe', 'pipe', 'pipe'] as const }),\n\t}).trim();\n\n/** The role a stage deploys as: `<project>-github-<stage>`, within IAM's 64. */\nexport function roleName(project: string, stage: string): string {\n\treturn `${project}-github-${stage}`\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+=,.@_-]/g, '-')\n\t\t.slice(0, 64);\n}\n\n/**\n * Who may assume the role: a workflow job running in this repository's\n * `<stage>` environment, and nothing else — not another branch's job, not\n * another environment's. That is what keeps a staging deploy from using the\n * production role.\n */\nexport function trustPolicy(\n\tproviderArn: string,\n\trepo: string,\n\tstage: string,\n): string {\n\treturn JSON.stringify({\n\t\tVersion: '2012-10-17',\n\t\tStatement: [\n\t\t\t{\n\t\t\t\tEffect: 'Allow',\n\t\t\t\tPrincipal: { Federated: providerArn },\n\t\t\t\tAction: 'sts:AssumeRoleWithWebIdentity',\n\t\t\t\tCondition: {\n\t\t\t\t\tStringEquals: {\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:aud`]: AUDIENCE,\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:sub`]: `repo:${repo}:environment:${stage}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t});\n}\n\n/** GitHub's OIDC provider in this account, created if it is not there. */\nexport async function ensureOidcProvider(iam: IAMClient): Promise<string> {\n\tconst { OpenIDConnectProviderList = [] } = await iam.send(\n\t\tnew ListOpenIDConnectProvidersCommand({}),\n\t);\n\tconst existing = OpenIDConnectProviderList.find((p) =>\n\t\tp.Arn?.endsWith(`oidc-provider/${GITHUB_OIDC_HOST}`),\n\t)?.Arn;\n\tif (existing) return existing;\n\n\tconst created = await iam.send(\n\t\tnew CreateOpenIDConnectProviderCommand({\n\t\t\tUrl: `https://${GITHUB_OIDC_HOST}`,\n\t\t\tClientIDList: [AUDIENCE],\n\t\t}),\n\t);\n\treturn created.OpenIDConnectProviderArn!;\n}\n\n/** The deploy role, created or brought back to this trust and policy. */\nexport async function ensureRole(\n\tiam: IAMClient,\n\tname: string,\n\ttrust: string,\n\tpolicyArn: string,\n): Promise<string> {\n\tlet arn: string;\n\ttry {\n\t\tconst { Role } = await iam.send(new GetRoleCommand({ RoleName: name }));\n\t\tawait iam.send(\n\t\t\tnew UpdateAssumeRolePolicyCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tPolicyDocument: trust,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t} catch (error) {\n\t\tif ((error as { name?: string }).name !== 'NoSuchEntityException') {\n\t\t\tthrow error;\n\t\t}\n\t\tconst { Role } = await iam.send(\n\t\t\tnew CreateRoleCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tAssumeRolePolicyDocument: trust,\n\t\t\t\tDescription: 'Deploys from GitHub Actions (gkm deploy:github)',\n\t\t\t\t// SST deploys can run long; the default hour is tight.\n\t\t\t\tMaxSessionDuration: 3600 * 2,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t}\n\n\t// Attaching an attached policy is a no-op, so this converges too.\n\tawait iam.send(\n\t\tnew AttachRolePolicyCommand({ RoleName: name, PolicyArn: policyArn }),\n\t);\n\treturn arn;\n}\n\n/**\n * An IAM client for the stage's account.\n *\n * `fromIni` for a named profile, deliberately: it resolves exactly that\n * profile — keys, assume-role, `credential_process` or SSO, whichever\n * ~/.aws/config says — and never falls back to AWS_* in the environment. The\n * provider chain checks the environment first, so exported staging keys would\n * quietly win over `--profile prod` and the production role would land in the\n * staging account.\n */\nexport async function iamFor(\n\tprofile?: string,\n\tendpoint?: string,\n): Promise<IAMClient> {\n\tconst config: IAMClientConfig = { region: 'us-east-1' };\n\tif (profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile });\n\t}\n\tif (endpoint) {\n\t\tconfig.endpoint = endpoint;\n\t\tconfig.credentials = { accessKeyId: 'test', secretAccessKey: 'test' };\n\t}\n\treturn new IAMClient(config);\n}\n\nexport async function deployGithubCommand(\n\toptions: DeployGithubOptions,\n\tdeps: { iam?: IAMClient; gh?: Gh; cwd?: string } = {},\n): Promise<{ roleArn?: string; repo: string }> {\n\tconst gh = deps.gh ?? defaultGh;\n\tconst { workspace } = await loadWorkspaceConfig(deps.cwd);\n\tassertDeployedStage(workspace.stages, options.stage);\n\n\tconst repo =\n\t\toptions.repo ??\n\t\tgh(['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner']);\n\tconst role = roleName(workspace.name, options.stage);\n\tconst policyArn = options.policyArn ?? DEFAULT_POLICY_ARN;\n\t// Read through the keystore so a key still at the place keys used to be kept\n\t// is found, and copied to where it is kept now.\n\tconst key = await readKey(options.stage, keystoreProject(workspace));\n\tconst keyPath = getKeyPath(options.stage, keystoreProject(workspace));\n\tconst hasKey = key !== null;\n\t// A stage whose secrets are in a store is read from there by the deploy job,\n\t// with the role; it needs no key on GitHub.\n\tconst remote = isRemoteStore(workspace, options.stage);\n\t// Read from the stage's own store, with the same credentials the role is\n\t// created with: what the deploy job will find there.\n\tconst store = await secretsStoreFor(workspace, options.stage, {\n\t\t...(options.profile ? { profile: options.profile } : {}),\n\t});\n\tconst hasSecrets = remote && (await store.read(options.stage)) !== null;\n\tconst via = options.profile\n\t\t? `profile \"${options.profile}\"`\n\t\t: 'the default credentials';\n\n\tlogger.log(`\\n🔐 GitHub → AWS for stage \"${options.stage}\"\\n`);\n\tlogger.log(` Repository: ${repo}`);\n\tlogger.log(` AWS profile: ${options.profile ?? '(default credentials)'}`);\n\tlogger.log(` Role: ${role}`);\n\tlogger.log(\n\t\t` Policy: ${policyArn}${options.policyArn ? '' : ' (default; --policy-arn to narrow)'}`,\n\t);\n\tlogger.log(` Trusted by: repo:${repo}:environment:${options.stage} only`);\n\tif (remote) {\n\t\tlogger.log(\n\t\t\t` Secrets: ${hasSecrets ? `in the store (${store.name}), read with ${via}` : `none in the store yet — gkm secrets:set <KEY> '…' --stage ${options.stage}`}`,\n\t\t);\n\t} else {\n\t\tlogger.log(\n\t\t\t` Secrets key: ${hasKey ? keyPath : `none at ${keyPath} — run gkm secrets:init --stage ${options.stage} first`}`,\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: nothing changed.\\n');\n\t\treturn { repo };\n\t}\n\n\tconst iam = deps.iam ?? (await iamFor(options.profile));\n\tconst providerArn = await ensureOidcProvider(iam).catch((error) => {\n\t\t// The first AWS call is where an expired SSO login surfaces; the SDK's\n\t\t// message does not say which profile, and this command knows.\n\t\tif (/SSO session/i.test(String(error?.message)) && options.profile) {\n\t\t\tthrow new SsoSessionExpired(options.profile);\n\t\t}\n\t\tthrow error;\n\t});\n\tconst roleArn = await ensureRole(\n\t\tiam,\n\t\trole,\n\t\ttrustPolicy(providerArn, repo, options.stage),\n\t\tpolicyArn,\n\t);\n\tlogger.log(`\\n ✓ AWS: ${roleArn}`);\n\n\t// The environment the generated deploy workflow runs the stage in.\n\tgh(['api', '--method', 'PUT', `repos/${repo}/environments/${options.stage}`]);\n\tgh([\n\t\t'variable',\n\t\t'set',\n\t\t'AWS_ROLE_ARN',\n\t\t'--env',\n\t\toptions.stage,\n\t\t'--repo',\n\t\trepo,\n\t\t'--body',\n\t\troleArn,\n\t]);\n\tlogger.log(` ✓ GitHub: environment \"${options.stage}\", AWS_ROLE_ARN`);\n\n\tif (remote) {\n\t\t// Nothing to send: the deploy job reads the stage's store itself.\n\t\tif (!hasSecrets) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ The \"${options.stage}\" store holds no secrets yet; set them with gkm secrets:set <KEY> '…' --stage ${options.stage}${options.profile ? ` (AWS_PROFILE=${options.profile})` : ''}.`,\n\t\t\t);\n\t\t}\n\t} else if (hasKey) {\n\t\t// Through stdin, so the key is never an argument a process list shows.\n\t\tgh(\n\t\t\t[\n\t\t\t\t'secret',\n\t\t\t\t'set',\n\t\t\t\t'GKM_SECRETS_KEY',\n\t\t\t\t'--env',\n\t\t\t\toptions.stage,\n\t\t\t\t'--repo',\n\t\t\t\trepo,\n\t\t\t],\n\t\t\tkey!,\n\t\t);\n\t\tlogger.log(' ✓ GitHub: GKM_SECRETS_KEY');\n\t} else {\n\t\tlogger.log(\n\t\t\t` ⚠ No secrets key for \"${options.stage}\"; run gkm secrets:init --stage ${options.stage}, then this again.`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t`\\n Protect it: add required reviewers to the \"${options.stage}\" environment in the repository settings.\\n`,\n\t);\n\treturn { roleArn, repo };\n}\n\n/** The profile's SSO login has lapsed; the fix is one command away. */\nexport class SsoSessionExpired extends Error {\n\tconstructor(readonly profile: string) {\n\t\tsuper(\n\t\t\t`The SSO session for profile \"${profile}\" has expired or is invalid. Run: aws sso login --profile ${profile}`,\n\t\t);\n\t\tthis.name = 'SsoSessionExpired';\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"github-BchWoiVx.cjs","names":["execFileSync","ListOpenIDConnectProvidersCommand","CreateOpenIDConnectProviderCommand","GetRoleCommand","UpdateAssumeRolePolicyCommand","CreateRoleCommand","AttachRolePolicyCommand","IAMClient","loadWorkspaceConfig","readKey","keystoreProject","getKeyPath","isRemoteStore","secretsStoreFor"],"sources":["../src/deploy/github.ts"],"sourcesContent":["/**\n * `gkm deploy:github` — let GitHub Actions deploy one stage, with no keys.\n *\n * A stage usually lives in its own AWS account — staging in one, production in\n * another — so this runs once per stage, with that account's profile:\n *\n * gkm deploy:github --stage staging --profile acme-dev\n * gkm deploy:github --stage prod --profile acme-prod\n *\n * In the stage's account it makes sure GitHub's OIDC provider exists, and a\n * role that only this repository's `<stage>` environment can assume. On\n * GitHub it creates that environment and gives it what the generated deploy\n * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in\n * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to\n * SSM the deploy job pulls them with the role instead, so no key is handed to\n * GitHub, and this pushes the stage's local secrets to SSM in the same account,\n * with the same profile. Re-running it converges rather than duplicating.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n\tAttachRolePolicyCommand,\n\tCreateOpenIDConnectProviderCommand,\n\tCreateRoleCommand,\n\tGetRoleCommand,\n\tIAMClient,\n\ttype IAMClientConfig,\n\tListOpenIDConnectProvidersCommand,\n\tUpdateAssumeRolePolicyCommand,\n} from '@aws-sdk/client-iam';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { getKeyPath, keystoreProject, readKey } from '../secrets/keystore.js';\nimport { isRemoteStore, secretsStoreFor } from '../secrets/store.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\n\nconst logger = console;\n\nconst GITHUB_OIDC_HOST = 'token.actions.githubusercontent.com';\nconst AUDIENCE = 'sts.amazonaws.com';\n\n/**\n * What SST needs to create a stack is most of AWS, so this is the default —\n * said out loud in the output, and replaceable with `--policy-arn`.\n */\nexport const DEFAULT_POLICY_ARN = 'arn:aws:iam::aws:policy/AdministratorAccess';\n\nexport interface DeployGithubOptions {\n\tstage: string;\n\t/** The AWS profile for the stage's account. */\n\tprofile?: string;\n\t/** `owner/name`; defaults to the repository `gh` sees here. */\n\trepo?: string;\n\t/** The policy the deploy role gets. */\n\tpolicyArn?: string;\n\tdryRun?: boolean;\n}\n\n/** Runs `gh` with the given arguments and optional stdin, returning stdout. */\nexport type Gh = (args: string[], input?: string) => string;\n\nconst defaultGh: Gh = (args, input) =>\n\texecFileSync('gh', args, {\n\t\tencoding: 'utf-8',\n\t\t...(input === undefined\n\t\t\t? {}\n\t\t\t: { input, stdio: ['pipe', 'pipe', 'pipe'] as const }),\n\t}).trim();\n\n/** The role a stage deploys as: `<project>-github-<stage>`, within IAM's 64. */\nexport function roleName(project: string, stage: string): string {\n\treturn `${project}-github-${stage}`\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+=,.@_-]/g, '-')\n\t\t.slice(0, 64);\n}\n\n/**\n * Who may assume the role: a workflow job running in this repository's\n * `<stage>` environment, and nothing else — not another branch's job, not\n * another environment's. That is what keeps a staging deploy from using the\n * production role.\n */\nexport function trustPolicy(\n\tproviderArn: string,\n\trepo: string,\n\tstage: string,\n): string {\n\treturn JSON.stringify({\n\t\tVersion: '2012-10-17',\n\t\tStatement: [\n\t\t\t{\n\t\t\t\tEffect: 'Allow',\n\t\t\t\tPrincipal: { Federated: providerArn },\n\t\t\t\tAction: 'sts:AssumeRoleWithWebIdentity',\n\t\t\t\tCondition: {\n\t\t\t\t\tStringEquals: {\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:aud`]: AUDIENCE,\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:sub`]: `repo:${repo}:environment:${stage}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t});\n}\n\n/** GitHub's OIDC provider in this account, created if it is not there. */\nexport async function ensureOidcProvider(iam: IAMClient): Promise<string> {\n\tconst { OpenIDConnectProviderList = [] } = await iam.send(\n\t\tnew ListOpenIDConnectProvidersCommand({}),\n\t);\n\tconst existing = OpenIDConnectProviderList.find((p) =>\n\t\tp.Arn?.endsWith(`oidc-provider/${GITHUB_OIDC_HOST}`),\n\t)?.Arn;\n\tif (existing) return existing;\n\n\tconst created = await iam.send(\n\t\tnew CreateOpenIDConnectProviderCommand({\n\t\t\tUrl: `https://${GITHUB_OIDC_HOST}`,\n\t\t\tClientIDList: [AUDIENCE],\n\t\t}),\n\t);\n\treturn created.OpenIDConnectProviderArn!;\n}\n\n/** The deploy role, created or brought back to this trust and policy. */\nexport async function ensureRole(\n\tiam: IAMClient,\n\tname: string,\n\ttrust: string,\n\tpolicyArn: string,\n): Promise<string> {\n\tlet arn: string;\n\ttry {\n\t\tconst { Role } = await iam.send(new GetRoleCommand({ RoleName: name }));\n\t\tawait iam.send(\n\t\t\tnew UpdateAssumeRolePolicyCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tPolicyDocument: trust,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t} catch (error) {\n\t\tif ((error as { name?: string }).name !== 'NoSuchEntityException') {\n\t\t\tthrow error;\n\t\t}\n\t\tconst { Role } = await iam.send(\n\t\t\tnew CreateRoleCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tAssumeRolePolicyDocument: trust,\n\t\t\t\tDescription: 'Deploys from GitHub Actions (gkm deploy:github)',\n\t\t\t\t// SST deploys can run long; the default hour is tight.\n\t\t\t\tMaxSessionDuration: 3600 * 2,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t}\n\n\t// Attaching an attached policy is a no-op, so this converges too.\n\tawait iam.send(\n\t\tnew AttachRolePolicyCommand({ RoleName: name, PolicyArn: policyArn }),\n\t);\n\treturn arn;\n}\n\n/**\n * An IAM client for the stage's account.\n *\n * `fromIni` for a named profile, deliberately: it resolves exactly that\n * profile — keys, assume-role, `credential_process` or SSO, whichever\n * ~/.aws/config says — and never falls back to AWS_* in the environment. The\n * provider chain checks the environment first, so exported staging keys would\n * quietly win over `--profile prod` and the production role would land in the\n * staging account.\n */\nexport async function iamFor(\n\tprofile?: string,\n\tendpoint?: string,\n): Promise<IAMClient> {\n\tconst config: IAMClientConfig = { region: 'us-east-1' };\n\tif (profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile });\n\t}\n\tif (endpoint) {\n\t\tconfig.endpoint = endpoint;\n\t\tconfig.credentials = { accessKeyId: 'test', secretAccessKey: 'test' };\n\t}\n\treturn new IAMClient(config);\n}\n\nexport async function deployGithubCommand(\n\toptions: DeployGithubOptions,\n\tdeps: { iam?: IAMClient; gh?: Gh; cwd?: string } = {},\n): Promise<{ roleArn?: string; repo: string }> {\n\tconst gh = deps.gh ?? defaultGh;\n\tconst { workspace } = await loadWorkspaceConfig(deps.cwd);\n\tassertDeployedStage(workspace.stages, options.stage);\n\n\tconst repo =\n\t\toptions.repo ??\n\t\tgh(['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner']);\n\tconst role = roleName(workspace.name, options.stage);\n\tconst policyArn = options.policyArn ?? DEFAULT_POLICY_ARN;\n\t// Read through the keystore so a key still at the place keys used to be kept\n\t// is found, and copied to where it is kept now.\n\tconst key = await readKey(options.stage, keystoreProject(workspace));\n\tconst keyPath = getKeyPath(options.stage, keystoreProject(workspace));\n\tconst hasKey = key !== null;\n\t// A stage whose secrets are in a store is read from there by the deploy job,\n\t// with the role; it needs no key on GitHub.\n\tconst remote = isRemoteStore(workspace, options.stage);\n\t// Read from the stage's own store, with the same credentials the role is\n\t// created with: what the deploy job will find there.\n\tconst store = await secretsStoreFor(workspace, options.stage, {\n\t\t...(options.profile ? { profile: options.profile } : {}),\n\t});\n\tconst hasSecrets = remote && (await store.read(options.stage)) !== null;\n\tconst via = options.profile\n\t\t? `profile \"${options.profile}\"`\n\t\t: 'the default credentials';\n\n\tlogger.log(`\\n🔐 GitHub → AWS for stage \"${options.stage}\"\\n`);\n\tlogger.log(` Repository: ${repo}`);\n\tlogger.log(` AWS profile: ${options.profile ?? '(default credentials)'}`);\n\tlogger.log(` Role: ${role}`);\n\tlogger.log(\n\t\t` Policy: ${policyArn}${options.policyArn ? '' : ' (default; --policy-arn to narrow)'}`,\n\t);\n\tlogger.log(` Trusted by: repo:${repo}:environment:${options.stage} only`);\n\tif (remote) {\n\t\tlogger.log(\n\t\t\t` Secrets: ${hasSecrets ? `in the store (${store.name}), read with ${via}` : `none in the store yet — gkm secrets:set <KEY> '…' --stage ${options.stage}`}`,\n\t\t);\n\t} else {\n\t\tlogger.log(\n\t\t\t` Secrets key: ${hasKey ? keyPath : `none at ${keyPath} — run gkm secrets:init --stage ${options.stage} first`}`,\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: nothing changed.\\n');\n\t\treturn { repo };\n\t}\n\n\tconst iam = deps.iam ?? (await iamFor(options.profile));\n\tconst providerArn = await ensureOidcProvider(iam).catch((error) => {\n\t\t// The first AWS call is where an expired SSO login surfaces; the SDK's\n\t\t// message does not say which profile, and this command knows.\n\t\tif (/SSO session/i.test(String(error?.message)) && options.profile) {\n\t\t\tthrow new SsoSessionExpired(options.profile);\n\t\t}\n\t\tthrow error;\n\t});\n\tconst roleArn = await ensureRole(\n\t\tiam,\n\t\trole,\n\t\ttrustPolicy(providerArn, repo, options.stage),\n\t\tpolicyArn,\n\t);\n\tlogger.log(`\\n ✓ AWS: ${roleArn}`);\n\n\t// The environment the generated deploy workflow runs the stage in.\n\tgh(['api', '--method', 'PUT', `repos/${repo}/environments/${options.stage}`]);\n\tgh([\n\t\t'variable',\n\t\t'set',\n\t\t'AWS_ROLE_ARN',\n\t\t'--env',\n\t\toptions.stage,\n\t\t'--repo',\n\t\trepo,\n\t\t'--body',\n\t\troleArn,\n\t]);\n\tlogger.log(` ✓ GitHub: environment \"${options.stage}\", AWS_ROLE_ARN`);\n\n\tif (remote) {\n\t\t// Nothing to send: the deploy job reads the stage's store itself.\n\t\tif (!hasSecrets) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ The \"${options.stage}\" store holds no secrets yet; set them with gkm secrets:set <KEY> '…' --stage ${options.stage}${options.profile ? ` (AWS_PROFILE=${options.profile})` : ''}.`,\n\t\t\t);\n\t\t}\n\t} else if (hasKey) {\n\t\t// Through stdin, so the key is never an argument a process list shows.\n\t\tgh(\n\t\t\t[\n\t\t\t\t'secret',\n\t\t\t\t'set',\n\t\t\t\t'GKM_SECRETS_KEY',\n\t\t\t\t'--env',\n\t\t\t\toptions.stage,\n\t\t\t\t'--repo',\n\t\t\t\trepo,\n\t\t\t],\n\t\t\tkey!,\n\t\t);\n\t\tlogger.log(' ✓ GitHub: GKM_SECRETS_KEY');\n\t} else {\n\t\tlogger.log(\n\t\t\t` ⚠ No secrets key for \"${options.stage}\"; run gkm secrets:init --stage ${options.stage}, then this again.`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t`\\n Protect it: add required reviewers to the \"${options.stage}\" environment in the repository settings.\\n`,\n\t);\n\treturn { roleArn, repo };\n}\n\n/** The profile's SSO login has lapsed; the fix is one command away. */\nexport class SsoSessionExpired extends Error {\n\tconstructor(readonly profile: string) {\n\t\tsuper(\n\t\t\t`The SSO session for profile \"${profile}\" has expired or is invalid. Run: aws sso login --profile ${profile}`,\n\t\t);\n\t\tthis.name = 'SsoSessionExpired';\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,SAAS;AAEf,MAAM,mBAAmB;AACzB,MAAM,WAAW;AAsBjB,MAAM,aAAiB,MAAM,WAAA,GAC5BA,mBAAAA,aAAAA,CAAa,MAAM,MAAM;CACxB,UAAU;CACV,GAAI,UAAU,KAAA,IACX,CAAC,IACD;EAAE;EAAO,OAAO;GAAC;GAAQ;GAAQ;EAAM;CAAW;AACtD,CAAC,CAAC,CAAC,KAAK;;AAGT,SAAgB,SAAS,SAAiB,OAAuB;CAChE,OAAO,GAAG,QAAQ,UAAU,QAC1B,YAAY,CAAC,CACb,QAAQ,qBAAqB,GAAG,CAAC,CACjC,MAAM,GAAG,EAAE;AACd;;;;;;;AAQA,SAAgB,YACf,aACA,MACA,OACS;CACT,OAAO,KAAK,UAAU;EACrB,SAAS;EACT,WAAW,CACV;GACC,QAAQ;GACR,WAAW,EAAE,WAAW,YAAY;GACpC,QAAQ;GACR,WAAW,EACV,cAAc;KACZ,GAAG,iBAAiB,QAAQ;KAC5B,GAAG,iBAAiB,QAAQ,QAAQ,KAAK,eAAe;GAC1D,EACD;EACD,CACD;CACD,CAAC;AACF;;AAGA,eAAsB,mBAAmB,KAAiC;CACzE,MAAM,EAAE,4BAA4B,CAAC,MAAM,MAAM,IAAI,KACpD,IAAIC,oBAAAA,kCAAkC,CAAC,CAAC,CACzC;CACA,MAAM,WAAW,0BAA0B,MAAM,MAChD,EAAE,KAAK,SAAS,iBAAiB,kBAAkB,CACpD,CAAC,EAAE;CACH,IAAI,UAAU,OAAO;CAQrB,QAAO,MANe,IAAI,KACzB,IAAIC,oBAAAA,mCAAmC;EACtC,KAAK,WAAW;EAChB,cAAc,CAAC,QAAQ;CACxB,CAAC,CACF,EAAA,CACe;AAChB;;AAGA,eAAsB,WACrB,KACA,MACA,OACA,WACkB;CAClB,IAAI;CACJ,IAAI;EACH,MAAM,EAAE,SAAS,MAAM,IAAI,KAAK,IAAIC,oBAAAA,eAAe,EAAE,UAAU,KAAK,CAAC,CAAC;EACtE,MAAM,IAAI,KACT,IAAIC,oBAAAA,8BAA8B;GACjC,UAAU;GACV,gBAAgB;EACjB,CAAC,CACF;EACA,MAAM,KAAM;CACb,SAAS,OAAO;EACf,IAAK,MAA4B,SAAS,yBACzC,MAAM;EAEP,MAAM,EAAE,SAAS,MAAM,IAAI,KAC1B,IAAIC,oBAAAA,kBAAkB;GACrB,UAAU;GACV,0BAA0B;GAC1B,aAAa;GAEb,oBAAoB;EACrB,CAAC,CACF;EACA,MAAM,KAAM;CACb;CAGA,MAAM,IAAI,KACT,IAAIC,oBAAAA,wBAAwB;EAAE,UAAU;EAAM,WAAW;CAAU,CAAC,CACrE;CACA,OAAO;AACR;;;;;;;;;;;AAYA,eAAsB,OACrB,SACA,UACqB;CACrB,MAAM,SAA0B,EAAE,QAAQ,YAAY;CACtD,IAAI,SAAS;EACZ,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,OAAO,cAAc,QAAQ,EAAE,QAAQ,CAAC;CACzC;CACA,IAAI,UAAU;EACb,OAAO,WAAW;EAClB,OAAO,cAAc;GAAE,aAAa;GAAQ,iBAAiB;EAAO;CACrE;CACA,OAAO,IAAIC,oBAAAA,UAAU,MAAM;AAC5B;AAEA,eAAsB,oBACrB,SACA,OAAmD,CAAC,GACN;CAC9C,MAAM,KAAK,KAAK,MAAM;CACtB,MAAM,EAAE,cAAc,MAAMC,eAAAA,oBAAoB,KAAK,GAAG;CACxD,kBAAA,oBAAoB,UAAU,QAAQ,QAAQ,KAAK;CAEnD,MAAM,OACL,QAAQ,QACR,GAAG;EAAC;EAAQ;EAAQ;EAAU;EAAiB;EAAM;CAAgB,CAAC;CACvE,MAAM,OAAO,SAAS,UAAU,MAAM,QAAQ,KAAK;CACnD,MAAM,YAAY,QAAQ,aAAA;CAG1B,MAAM,MAAM,MAAMC,cAAAA,QAAQ,QAAQ,OAAOC,cAAAA,gBAAgB,SAAS,CAAC;CACnE,MAAM,UAAUC,cAAAA,WAAW,QAAQ,OAAOD,cAAAA,gBAAgB,SAAS,CAAC;CACpE,MAAM,SAAS,QAAQ;CAGvB,MAAM,SAASE,cAAAA,cAAc,WAAW,QAAQ,KAAK;CAGrD,MAAM,QAAQ,MAAMC,cAAAA,gBAAgB,WAAW,QAAQ,OAAO,EAC7D,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC,EACvD,CAAC;CACD,MAAM,aAAa,UAAW,MAAM,MAAM,KAAK,QAAQ,KAAK,MAAO;CACnE,MAAM,MAAM,QAAQ,UACjB,YAAY,QAAQ,QAAQ,KAC5B;CAEH,OAAO,IAAI,gCAAgC,QAAQ,MAAM,IAAI;CAC7D,OAAO,IAAI,mBAAmB,MAAM;CACpC,OAAO,IAAI,mBAAmB,QAAQ,WAAW,yBAAyB;CAC1E,OAAO,IAAI,mBAAmB,MAAM;CACpC,OAAO,IACN,mBAAmB,YAAY,QAAQ,YAAY,KAAK,uCACzD;CACA,OAAO,IAAI,wBAAwB,KAAK,eAAe,QAAQ,MAAM,MAAM;CAC3E,IAAI,QACH,OAAO,IACN,mBAAmB,aAAa,iBAAiB,MAAM,KAAK,eAAe,QAAQ,6DAA6D,QAAQ,SACzJ;MAEA,OAAO,IACN,mBAAmB,SAAS,UAAU,WAAW,QAAQ,kCAAkC,QAAQ,MAAM,SAC1G;CAGD,IAAI,QAAQ,QAAQ;EACnB,OAAO,IAAI,mCAAmC;EAC9C,OAAO,EAAE,KAAK;CACf;CAEA,MAAM,MAAM,KAAK,OAAQ,MAAM,OAAO,QAAQ,OAAO;CASrD,MAAM,UAAU,MAAM,WACrB,KACA,MACA,YAAY,MAXa,mBAAmB,GAAG,CAAC,CAAC,OAAO,UAAU;EAGlE,IAAI,eAAe,KAAK,OAAO,OAAO,OAAO,CAAC,KAAK,QAAQ,SAC1D,MAAM,IAAI,kBAAkB,QAAQ,OAAO;EAE5C,MAAM;CACP,CAAC,GAIyB,MAAM,QAAQ,KAAK,GAC5C,SACD;CACA,OAAO,IAAI,cAAc,SAAS;CAGlC,GAAG;EAAC;EAAO;EAAY;EAAO,SAAS,KAAK,gBAAgB,QAAQ;CAAO,CAAC;CAC5E,GAAG;EACF;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;CACD,CAAC;CACD,OAAO,IAAI,4BAA4B,QAAQ,MAAM,gBAAgB;CAErE,IAAI,QAEC;MAAA,CAAC,YACJ,OAAO,IACN,YAAY,QAAQ,MAAM,gFAAgF,QAAQ,QAAQ,QAAQ,UAAU,iBAAiB,QAAQ,QAAQ,KAAK,GAAG,EACtL;CAAA,OAEK,IAAI,QAAQ;EAElB,GACC;GACC;GACA;GACA;GACA;GACA,QAAQ;GACR;GACA;EACD,GACA,GACD;EACA,OAAO,IAAI,6BAA6B;CACzC,OACC,OAAO,IACN,2BAA2B,QAAQ,MAAM,kCAAkC,QAAQ,MAAM,mBAC1F;CAGD,OAAO,IACN,kDAAkD,QAAQ,MAAM,4CACjE;CACA,OAAO;EAAE;EAAS;CAAK;AACxB;;AAGA,IAAa,oBAAb,cAAuC,MAAM;CACvB;CAArB,YAAY,SAA0B;EACrC,MACC,gCAAgC,QAAQ,4DAA4D,SACrG;EAHoB,KAAA,UAAA;EAIpB,KAAK,OAAO;CACb;AACD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { k as assertDeployedStage } from "./workspace-
|
|
1
|
+
import { k as assertDeployedStage } from "./workspace-C7NqCsQF.mjs";
|
|
2
2
|
import { loadWorkspaceConfig } from "./config.mjs";
|
|
3
|
-
import { Bt as
|
|
3
|
+
import { Bt as keystoreProject, Ft as isRemoteStore, Ht as readKey, It as secretsStoreFor, zt as getKeyPath } from "./state-BJFherj1.mjs";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { AttachRolePolicyCommand, CreateOpenIDConnectProviderCommand, CreateRoleCommand, GetRoleCommand, IAMClient, ListOpenIDConnectProvidersCommand, UpdateAssumeRolePolicyCommand } from "@aws-sdk/client-iam";
|
|
6
6
|
//#region src/deploy/github.ts
|
|
@@ -210,4 +210,4 @@ var SsoSessionExpired = class extends Error {
|
|
|
210
210
|
//#endregion
|
|
211
211
|
export { deployGithubCommand };
|
|
212
212
|
|
|
213
|
-
//# sourceMappingURL=github-
|
|
213
|
+
//# sourceMappingURL=github-CqYOP8cI.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-DtymyOcH.mjs","names":[],"sources":["../src/deploy/github.ts"],"sourcesContent":["/**\n * `gkm deploy:github` — let GitHub Actions deploy one stage, with no keys.\n *\n * A stage usually lives in its own AWS account — staging in one, production in\n * another — so this runs once per stage, with that account's profile:\n *\n * gkm deploy:github --stage staging --profile acme-dev\n * gkm deploy:github --stage prod --profile acme-prod\n *\n * In the stage's account it makes sure GitHub's OIDC provider exists, and a\n * role that only this repository's `<stage>` environment can assume. On\n * GitHub it creates that environment and gives it what the generated deploy\n * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in\n * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to\n * SSM the deploy job pulls them with the role instead, so no key is handed to\n * GitHub, and this pushes the stage's local secrets to SSM in the same account,\n * with the same profile. Re-running it converges rather than duplicating.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n\tAttachRolePolicyCommand,\n\tCreateOpenIDConnectProviderCommand,\n\tCreateRoleCommand,\n\tGetRoleCommand,\n\tIAMClient,\n\ttype IAMClientConfig,\n\tListOpenIDConnectProvidersCommand,\n\tUpdateAssumeRolePolicyCommand,\n} from '@aws-sdk/client-iam';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { getKeyPath, keystoreProject, readKey } from '../secrets/keystore.js';\nimport { isRemoteStore, secretsStoreFor } from '../secrets/store.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\n\nconst logger = console;\n\nconst GITHUB_OIDC_HOST = 'token.actions.githubusercontent.com';\nconst AUDIENCE = 'sts.amazonaws.com';\n\n/**\n * What SST needs to create a stack is most of AWS, so this is the default —\n * said out loud in the output, and replaceable with `--policy-arn`.\n */\nexport const DEFAULT_POLICY_ARN = 'arn:aws:iam::aws:policy/AdministratorAccess';\n\nexport interface DeployGithubOptions {\n\tstage: string;\n\t/** The AWS profile for the stage's account. */\n\tprofile?: string;\n\t/** `owner/name`; defaults to the repository `gh` sees here. */\n\trepo?: string;\n\t/** The policy the deploy role gets. */\n\tpolicyArn?: string;\n\tdryRun?: boolean;\n}\n\n/** Runs `gh` with the given arguments and optional stdin, returning stdout. */\nexport type Gh = (args: string[], input?: string) => string;\n\nconst defaultGh: Gh = (args, input) =>\n\texecFileSync('gh', args, {\n\t\tencoding: 'utf-8',\n\t\t...(input === undefined\n\t\t\t? {}\n\t\t\t: { input, stdio: ['pipe', 'pipe', 'pipe'] as const }),\n\t}).trim();\n\n/** The role a stage deploys as: `<project>-github-<stage>`, within IAM's 64. */\nexport function roleName(project: string, stage: string): string {\n\treturn `${project}-github-${stage}`\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+=,.@_-]/g, '-')\n\t\t.slice(0, 64);\n}\n\n/**\n * Who may assume the role: a workflow job running in this repository's\n * `<stage>` environment, and nothing else — not another branch's job, not\n * another environment's. That is what keeps a staging deploy from using the\n * production role.\n */\nexport function trustPolicy(\n\tproviderArn: string,\n\trepo: string,\n\tstage: string,\n): string {\n\treturn JSON.stringify({\n\t\tVersion: '2012-10-17',\n\t\tStatement: [\n\t\t\t{\n\t\t\t\tEffect: 'Allow',\n\t\t\t\tPrincipal: { Federated: providerArn },\n\t\t\t\tAction: 'sts:AssumeRoleWithWebIdentity',\n\t\t\t\tCondition: {\n\t\t\t\t\tStringEquals: {\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:aud`]: AUDIENCE,\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:sub`]: `repo:${repo}:environment:${stage}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t});\n}\n\n/** GitHub's OIDC provider in this account, created if it is not there. */\nexport async function ensureOidcProvider(iam: IAMClient): Promise<string> {\n\tconst { OpenIDConnectProviderList = [] } = await iam.send(\n\t\tnew ListOpenIDConnectProvidersCommand({}),\n\t);\n\tconst existing = OpenIDConnectProviderList.find((p) =>\n\t\tp.Arn?.endsWith(`oidc-provider/${GITHUB_OIDC_HOST}`),\n\t)?.Arn;\n\tif (existing) return existing;\n\n\tconst created = await iam.send(\n\t\tnew CreateOpenIDConnectProviderCommand({\n\t\t\tUrl: `https://${GITHUB_OIDC_HOST}`,\n\t\t\tClientIDList: [AUDIENCE],\n\t\t}),\n\t);\n\treturn created.OpenIDConnectProviderArn!;\n}\n\n/** The deploy role, created or brought back to this trust and policy. */\nexport async function ensureRole(\n\tiam: IAMClient,\n\tname: string,\n\ttrust: string,\n\tpolicyArn: string,\n): Promise<string> {\n\tlet arn: string;\n\ttry {\n\t\tconst { Role } = await iam.send(new GetRoleCommand({ RoleName: name }));\n\t\tawait iam.send(\n\t\t\tnew UpdateAssumeRolePolicyCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tPolicyDocument: trust,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t} catch (error) {\n\t\tif ((error as { name?: string }).name !== 'NoSuchEntityException') {\n\t\t\tthrow error;\n\t\t}\n\t\tconst { Role } = await iam.send(\n\t\t\tnew CreateRoleCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tAssumeRolePolicyDocument: trust,\n\t\t\t\tDescription: 'Deploys from GitHub Actions (gkm deploy:github)',\n\t\t\t\t// SST deploys can run long; the default hour is tight.\n\t\t\t\tMaxSessionDuration: 3600 * 2,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t}\n\n\t// Attaching an attached policy is a no-op, so this converges too.\n\tawait iam.send(\n\t\tnew AttachRolePolicyCommand({ RoleName: name, PolicyArn: policyArn }),\n\t);\n\treturn arn;\n}\n\n/**\n * An IAM client for the stage's account.\n *\n * `fromIni` for a named profile, deliberately: it resolves exactly that\n * profile — keys, assume-role, `credential_process` or SSO, whichever\n * ~/.aws/config says — and never falls back to AWS_* in the environment. The\n * provider chain checks the environment first, so exported staging keys would\n * quietly win over `--profile prod` and the production role would land in the\n * staging account.\n */\nexport async function iamFor(\n\tprofile?: string,\n\tendpoint?: string,\n): Promise<IAMClient> {\n\tconst config: IAMClientConfig = { region: 'us-east-1' };\n\tif (profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile });\n\t}\n\tif (endpoint) {\n\t\tconfig.endpoint = endpoint;\n\t\tconfig.credentials = { accessKeyId: 'test', secretAccessKey: 'test' };\n\t}\n\treturn new IAMClient(config);\n}\n\nexport async function deployGithubCommand(\n\toptions: DeployGithubOptions,\n\tdeps: { iam?: IAMClient; gh?: Gh; cwd?: string } = {},\n): Promise<{ roleArn?: string; repo: string }> {\n\tconst gh = deps.gh ?? defaultGh;\n\tconst { workspace } = await loadWorkspaceConfig(deps.cwd);\n\tassertDeployedStage(workspace.stages, options.stage);\n\n\tconst repo =\n\t\toptions.repo ??\n\t\tgh(['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner']);\n\tconst role = roleName(workspace.name, options.stage);\n\tconst policyArn = options.policyArn ?? DEFAULT_POLICY_ARN;\n\t// Read through the keystore so a key still at the place keys used to be kept\n\t// is found, and copied to where it is kept now.\n\tconst key = await readKey(options.stage, keystoreProject(workspace));\n\tconst keyPath = getKeyPath(options.stage, keystoreProject(workspace));\n\tconst hasKey = key !== null;\n\t// A stage whose secrets are in a store is read from there by the deploy job,\n\t// with the role; it needs no key on GitHub.\n\tconst remote = isRemoteStore(workspace, options.stage);\n\t// Read from the stage's own store, with the same credentials the role is\n\t// created with: what the deploy job will find there.\n\tconst store = await secretsStoreFor(workspace, options.stage, {\n\t\t...(options.profile ? { profile: options.profile } : {}),\n\t});\n\tconst hasSecrets = remote && (await store.read(options.stage)) !== null;\n\tconst via = options.profile\n\t\t? `profile \"${options.profile}\"`\n\t\t: 'the default credentials';\n\n\tlogger.log(`\\n🔐 GitHub → AWS for stage \"${options.stage}\"\\n`);\n\tlogger.log(` Repository: ${repo}`);\n\tlogger.log(` AWS profile: ${options.profile ?? '(default credentials)'}`);\n\tlogger.log(` Role: ${role}`);\n\tlogger.log(\n\t\t` Policy: ${policyArn}${options.policyArn ? '' : ' (default; --policy-arn to narrow)'}`,\n\t);\n\tlogger.log(` Trusted by: repo:${repo}:environment:${options.stage} only`);\n\tif (remote) {\n\t\tlogger.log(\n\t\t\t` Secrets: ${hasSecrets ? `in the store (${store.name}), read with ${via}` : `none in the store yet — gkm secrets:set <KEY> '…' --stage ${options.stage}`}`,\n\t\t);\n\t} else {\n\t\tlogger.log(\n\t\t\t` Secrets key: ${hasKey ? keyPath : `none at ${keyPath} — run gkm secrets:init --stage ${options.stage} first`}`,\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: nothing changed.\\n');\n\t\treturn { repo };\n\t}\n\n\tconst iam = deps.iam ?? (await iamFor(options.profile));\n\tconst providerArn = await ensureOidcProvider(iam).catch((error) => {\n\t\t// The first AWS call is where an expired SSO login surfaces; the SDK's\n\t\t// message does not say which profile, and this command knows.\n\t\tif (/SSO session/i.test(String(error?.message)) && options.profile) {\n\t\t\tthrow new SsoSessionExpired(options.profile);\n\t\t}\n\t\tthrow error;\n\t});\n\tconst roleArn = await ensureRole(\n\t\tiam,\n\t\trole,\n\t\ttrustPolicy(providerArn, repo, options.stage),\n\t\tpolicyArn,\n\t);\n\tlogger.log(`\\n ✓ AWS: ${roleArn}`);\n\n\t// The environment the generated deploy workflow runs the stage in.\n\tgh(['api', '--method', 'PUT', `repos/${repo}/environments/${options.stage}`]);\n\tgh([\n\t\t'variable',\n\t\t'set',\n\t\t'AWS_ROLE_ARN',\n\t\t'--env',\n\t\toptions.stage,\n\t\t'--repo',\n\t\trepo,\n\t\t'--body',\n\t\troleArn,\n\t]);\n\tlogger.log(` ✓ GitHub: environment \"${options.stage}\", AWS_ROLE_ARN`);\n\n\tif (remote) {\n\t\t// Nothing to send: the deploy job reads the stage's store itself.\n\t\tif (!hasSecrets) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ The \"${options.stage}\" store holds no secrets yet; set them with gkm secrets:set <KEY> '…' --stage ${options.stage}${options.profile ? ` (AWS_PROFILE=${options.profile})` : ''}.`,\n\t\t\t);\n\t\t}\n\t} else if (hasKey) {\n\t\t// Through stdin, so the key is never an argument a process list shows.\n\t\tgh(\n\t\t\t[\n\t\t\t\t'secret',\n\t\t\t\t'set',\n\t\t\t\t'GKM_SECRETS_KEY',\n\t\t\t\t'--env',\n\t\t\t\toptions.stage,\n\t\t\t\t'--repo',\n\t\t\t\trepo,\n\t\t\t],\n\t\t\tkey!,\n\t\t);\n\t\tlogger.log(' ✓ GitHub: GKM_SECRETS_KEY');\n\t} else {\n\t\tlogger.log(\n\t\t\t` ⚠ No secrets key for \"${options.stage}\"; run gkm secrets:init --stage ${options.stage}, then this again.`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t`\\n Protect it: add required reviewers to the \"${options.stage}\" environment in the repository settings.\\n`,\n\t);\n\treturn { roleArn, repo };\n}\n\n/** The profile's SSO login has lapsed; the fix is one command away. */\nexport class SsoSessionExpired extends Error {\n\tconstructor(readonly profile: string) {\n\t\tsuper(\n\t\t\t`The SSO session for profile \"${profile}\" has expired or is invalid. Run: aws sso login --profile ${profile}`,\n\t\t);\n\t\tthis.name = 'SsoSessionExpired';\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"github-CqYOP8cI.mjs","names":[],"sources":["../src/deploy/github.ts"],"sourcesContent":["/**\n * `gkm deploy:github` — let GitHub Actions deploy one stage, with no keys.\n *\n * A stage usually lives in its own AWS account — staging in one, production in\n * another — so this runs once per stage, with that account's profile:\n *\n * gkm deploy:github --stage staging --profile acme-dev\n * gkm deploy:github --stage prod --profile acme-prod\n *\n * In the stage's account it makes sure GitHub's OIDC provider exists, and a\n * role that only this repository's `<stage>` environment can assume. On\n * GitHub it creates that environment and gives it what the generated deploy\n * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in\n * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to\n * SSM the deploy job pulls them with the role instead, so no key is handed to\n * GitHub, and this pushes the stage's local secrets to SSM in the same account,\n * with the same profile. Re-running it converges rather than duplicating.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n\tAttachRolePolicyCommand,\n\tCreateOpenIDConnectProviderCommand,\n\tCreateRoleCommand,\n\tGetRoleCommand,\n\tIAMClient,\n\ttype IAMClientConfig,\n\tListOpenIDConnectProvidersCommand,\n\tUpdateAssumeRolePolicyCommand,\n} from '@aws-sdk/client-iam';\nimport { loadWorkspaceConfig } from '../config.js';\nimport { getKeyPath, keystoreProject, readKey } from '../secrets/keystore.js';\nimport { isRemoteStore, secretsStoreFor } from '../secrets/store.js';\nimport { assertDeployedStage } from '../workspace/stages.js';\n\nconst logger = console;\n\nconst GITHUB_OIDC_HOST = 'token.actions.githubusercontent.com';\nconst AUDIENCE = 'sts.amazonaws.com';\n\n/**\n * What SST needs to create a stack is most of AWS, so this is the default —\n * said out loud in the output, and replaceable with `--policy-arn`.\n */\nexport const DEFAULT_POLICY_ARN = 'arn:aws:iam::aws:policy/AdministratorAccess';\n\nexport interface DeployGithubOptions {\n\tstage: string;\n\t/** The AWS profile for the stage's account. */\n\tprofile?: string;\n\t/** `owner/name`; defaults to the repository `gh` sees here. */\n\trepo?: string;\n\t/** The policy the deploy role gets. */\n\tpolicyArn?: string;\n\tdryRun?: boolean;\n}\n\n/** Runs `gh` with the given arguments and optional stdin, returning stdout. */\nexport type Gh = (args: string[], input?: string) => string;\n\nconst defaultGh: Gh = (args, input) =>\n\texecFileSync('gh', args, {\n\t\tencoding: 'utf-8',\n\t\t...(input === undefined\n\t\t\t? {}\n\t\t\t: { input, stdio: ['pipe', 'pipe', 'pipe'] as const }),\n\t}).trim();\n\n/** The role a stage deploys as: `<project>-github-<stage>`, within IAM's 64. */\nexport function roleName(project: string, stage: string): string {\n\treturn `${project}-github-${stage}`\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9+=,.@_-]/g, '-')\n\t\t.slice(0, 64);\n}\n\n/**\n * Who may assume the role: a workflow job running in this repository's\n * `<stage>` environment, and nothing else — not another branch's job, not\n * another environment's. That is what keeps a staging deploy from using the\n * production role.\n */\nexport function trustPolicy(\n\tproviderArn: string,\n\trepo: string,\n\tstage: string,\n): string {\n\treturn JSON.stringify({\n\t\tVersion: '2012-10-17',\n\t\tStatement: [\n\t\t\t{\n\t\t\t\tEffect: 'Allow',\n\t\t\t\tPrincipal: { Federated: providerArn },\n\t\t\t\tAction: 'sts:AssumeRoleWithWebIdentity',\n\t\t\t\tCondition: {\n\t\t\t\t\tStringEquals: {\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:aud`]: AUDIENCE,\n\t\t\t\t\t\t[`${GITHUB_OIDC_HOST}:sub`]: `repo:${repo}:environment:${stage}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t});\n}\n\n/** GitHub's OIDC provider in this account, created if it is not there. */\nexport async function ensureOidcProvider(iam: IAMClient): Promise<string> {\n\tconst { OpenIDConnectProviderList = [] } = await iam.send(\n\t\tnew ListOpenIDConnectProvidersCommand({}),\n\t);\n\tconst existing = OpenIDConnectProviderList.find((p) =>\n\t\tp.Arn?.endsWith(`oidc-provider/${GITHUB_OIDC_HOST}`),\n\t)?.Arn;\n\tif (existing) return existing;\n\n\tconst created = await iam.send(\n\t\tnew CreateOpenIDConnectProviderCommand({\n\t\t\tUrl: `https://${GITHUB_OIDC_HOST}`,\n\t\t\tClientIDList: [AUDIENCE],\n\t\t}),\n\t);\n\treturn created.OpenIDConnectProviderArn!;\n}\n\n/** The deploy role, created or brought back to this trust and policy. */\nexport async function ensureRole(\n\tiam: IAMClient,\n\tname: string,\n\ttrust: string,\n\tpolicyArn: string,\n): Promise<string> {\n\tlet arn: string;\n\ttry {\n\t\tconst { Role } = await iam.send(new GetRoleCommand({ RoleName: name }));\n\t\tawait iam.send(\n\t\t\tnew UpdateAssumeRolePolicyCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tPolicyDocument: trust,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t} catch (error) {\n\t\tif ((error as { name?: string }).name !== 'NoSuchEntityException') {\n\t\t\tthrow error;\n\t\t}\n\t\tconst { Role } = await iam.send(\n\t\t\tnew CreateRoleCommand({\n\t\t\t\tRoleName: name,\n\t\t\t\tAssumeRolePolicyDocument: trust,\n\t\t\t\tDescription: 'Deploys from GitHub Actions (gkm deploy:github)',\n\t\t\t\t// SST deploys can run long; the default hour is tight.\n\t\t\t\tMaxSessionDuration: 3600 * 2,\n\t\t\t}),\n\t\t);\n\t\tarn = Role!.Arn!;\n\t}\n\n\t// Attaching an attached policy is a no-op, so this converges too.\n\tawait iam.send(\n\t\tnew AttachRolePolicyCommand({ RoleName: name, PolicyArn: policyArn }),\n\t);\n\treturn arn;\n}\n\n/**\n * An IAM client for the stage's account.\n *\n * `fromIni` for a named profile, deliberately: it resolves exactly that\n * profile — keys, assume-role, `credential_process` or SSO, whichever\n * ~/.aws/config says — and never falls back to AWS_* in the environment. The\n * provider chain checks the environment first, so exported staging keys would\n * quietly win over `--profile prod` and the production role would land in the\n * staging account.\n */\nexport async function iamFor(\n\tprofile?: string,\n\tendpoint?: string,\n): Promise<IAMClient> {\n\tconst config: IAMClientConfig = { region: 'us-east-1' };\n\tif (profile) {\n\t\tconst { fromIni } = await import('@aws-sdk/credential-providers');\n\t\tconfig.credentials = fromIni({ profile });\n\t}\n\tif (endpoint) {\n\t\tconfig.endpoint = endpoint;\n\t\tconfig.credentials = { accessKeyId: 'test', secretAccessKey: 'test' };\n\t}\n\treturn new IAMClient(config);\n}\n\nexport async function deployGithubCommand(\n\toptions: DeployGithubOptions,\n\tdeps: { iam?: IAMClient; gh?: Gh; cwd?: string } = {},\n): Promise<{ roleArn?: string; repo: string }> {\n\tconst gh = deps.gh ?? defaultGh;\n\tconst { workspace } = await loadWorkspaceConfig(deps.cwd);\n\tassertDeployedStage(workspace.stages, options.stage);\n\n\tconst repo =\n\t\toptions.repo ??\n\t\tgh(['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner']);\n\tconst role = roleName(workspace.name, options.stage);\n\tconst policyArn = options.policyArn ?? DEFAULT_POLICY_ARN;\n\t// Read through the keystore so a key still at the place keys used to be kept\n\t// is found, and copied to where it is kept now.\n\tconst key = await readKey(options.stage, keystoreProject(workspace));\n\tconst keyPath = getKeyPath(options.stage, keystoreProject(workspace));\n\tconst hasKey = key !== null;\n\t// A stage whose secrets are in a store is read from there by the deploy job,\n\t// with the role; it needs no key on GitHub.\n\tconst remote = isRemoteStore(workspace, options.stage);\n\t// Read from the stage's own store, with the same credentials the role is\n\t// created with: what the deploy job will find there.\n\tconst store = await secretsStoreFor(workspace, options.stage, {\n\t\t...(options.profile ? { profile: options.profile } : {}),\n\t});\n\tconst hasSecrets = remote && (await store.read(options.stage)) !== null;\n\tconst via = options.profile\n\t\t? `profile \"${options.profile}\"`\n\t\t: 'the default credentials';\n\n\tlogger.log(`\\n🔐 GitHub → AWS for stage \"${options.stage}\"\\n`);\n\tlogger.log(` Repository: ${repo}`);\n\tlogger.log(` AWS profile: ${options.profile ?? '(default credentials)'}`);\n\tlogger.log(` Role: ${role}`);\n\tlogger.log(\n\t\t` Policy: ${policyArn}${options.policyArn ? '' : ' (default; --policy-arn to narrow)'}`,\n\t);\n\tlogger.log(` Trusted by: repo:${repo}:environment:${options.stage} only`);\n\tif (remote) {\n\t\tlogger.log(\n\t\t\t` Secrets: ${hasSecrets ? `in the store (${store.name}), read with ${via}` : `none in the store yet — gkm secrets:set <KEY> '…' --stage ${options.stage}`}`,\n\t\t);\n\t} else {\n\t\tlogger.log(\n\t\t\t` Secrets key: ${hasKey ? keyPath : `none at ${keyPath} — run gkm secrets:init --stage ${options.stage} first`}`,\n\t\t);\n\t}\n\n\tif (options.dryRun) {\n\t\tlogger.log('\\n --dry-run: nothing changed.\\n');\n\t\treturn { repo };\n\t}\n\n\tconst iam = deps.iam ?? (await iamFor(options.profile));\n\tconst providerArn = await ensureOidcProvider(iam).catch((error) => {\n\t\t// The first AWS call is where an expired SSO login surfaces; the SDK's\n\t\t// message does not say which profile, and this command knows.\n\t\tif (/SSO session/i.test(String(error?.message)) && options.profile) {\n\t\t\tthrow new SsoSessionExpired(options.profile);\n\t\t}\n\t\tthrow error;\n\t});\n\tconst roleArn = await ensureRole(\n\t\tiam,\n\t\trole,\n\t\ttrustPolicy(providerArn, repo, options.stage),\n\t\tpolicyArn,\n\t);\n\tlogger.log(`\\n ✓ AWS: ${roleArn}`);\n\n\t// The environment the generated deploy workflow runs the stage in.\n\tgh(['api', '--method', 'PUT', `repos/${repo}/environments/${options.stage}`]);\n\tgh([\n\t\t'variable',\n\t\t'set',\n\t\t'AWS_ROLE_ARN',\n\t\t'--env',\n\t\toptions.stage,\n\t\t'--repo',\n\t\trepo,\n\t\t'--body',\n\t\troleArn,\n\t]);\n\tlogger.log(` ✓ GitHub: environment \"${options.stage}\", AWS_ROLE_ARN`);\n\n\tif (remote) {\n\t\t// Nothing to send: the deploy job reads the stage's store itself.\n\t\tif (!hasSecrets) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚠ The \"${options.stage}\" store holds no secrets yet; set them with gkm secrets:set <KEY> '…' --stage ${options.stage}${options.profile ? ` (AWS_PROFILE=${options.profile})` : ''}.`,\n\t\t\t);\n\t\t}\n\t} else if (hasKey) {\n\t\t// Through stdin, so the key is never an argument a process list shows.\n\t\tgh(\n\t\t\t[\n\t\t\t\t'secret',\n\t\t\t\t'set',\n\t\t\t\t'GKM_SECRETS_KEY',\n\t\t\t\t'--env',\n\t\t\t\toptions.stage,\n\t\t\t\t'--repo',\n\t\t\t\trepo,\n\t\t\t],\n\t\t\tkey!,\n\t\t);\n\t\tlogger.log(' ✓ GitHub: GKM_SECRETS_KEY');\n\t} else {\n\t\tlogger.log(\n\t\t\t` ⚠ No secrets key for \"${options.stage}\"; run gkm secrets:init --stage ${options.stage}, then this again.`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t`\\n Protect it: add required reviewers to the \"${options.stage}\" environment in the repository settings.\\n`,\n\t);\n\treturn { roleArn, repo };\n}\n\n/** The profile's SSO login has lapsed; the fix is one command away. */\nexport class SsoSessionExpired extends Error {\n\tconstructor(readonly profile: string) {\n\t\tsuper(\n\t\t\t`The SSO session for profile \"${profile}\" has expired or is invalid. Run: aws sso login --profile ${profile}`,\n\t\t);\n\t\tthis.name = 'SsoSessionExpired';\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as WorkspaceInput, S as NormalizedWorkspace, T as WorkspaceConfig, a as Routes, k as Framework, l as AppsRecord, r as GkmConfig, v as InferredWorkspaceConfig, y as LoadedConfig } from "./types-BD1jgA85.cjs";
|
|
2
2
|
//#region src/workspace/publicEnv.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* All public env-var prefixes the toolbox understands.
|
|
@@ -166,4 +166,4 @@ declare function getEndpointForStage(dokployConfig: {
|
|
|
166
166
|
} | undefined, stage: string): string | undefined;
|
|
167
167
|
//#endregion
|
|
168
168
|
export { constructPatterns as a, getAppGkmConfig as c, processConfig as d, workspaceConstructGlobs as f, stripPublicPrefix as g, getPublicEnvPrefix as h, assertNoMovedDeployKeys as i, getEndpointForStage as l, PUBLIC_ENV_PREFIXES as m, allConstructGlobs as n, defineWorkspace as o, wrapSingleAppAsWorkspace as p, appConstructGlobs as r, getAppBuildOrder as s, DokployRegistryMoved as t, normalizeWorkspace as u };
|
|
169
|
-
//# sourceMappingURL=index-
|
|
169
|
+
//# sourceMappingURL=index-Bk3NY6DN.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-Bk3NY6DN.d.cts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC6ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBAgCX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;;;;;;;;cA8DU,6BAA6B;WACpB;EAArB,YAAqB;;;iBAUN,wBAAwB;iBAOxB,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBA+Ba,wBACf,WAAW;;;;;;;;;;;;iBAkBI,kBACf,WAAW,qBACX;;;;;;;iBAsBe,kBAAkB,WAAW;;iBAa7B,kBAAkB,QAAQ;;;;;iBAS1B,gBACf,WAAW,qBACX,kBACE;;;;;iBAgCa,iBAAiB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoD5B,oBACf;EACK;EAAmB,YAAY;eAEpC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as WorkspaceInput, S as NormalizedWorkspace, T as WorkspaceConfig, a as Routes, k as Framework, l as AppsRecord, r as GkmConfig, v as InferredWorkspaceConfig, y as LoadedConfig } from "./types-DkG5WW8l.mjs";
|
|
2
2
|
//#region src/workspace/publicEnv.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* All public env-var prefixes the toolbox understands.
|
|
@@ -166,4 +166,4 @@ declare function getEndpointForStage(dokployConfig: {
|
|
|
166
166
|
} | undefined, stage: string): string | undefined;
|
|
167
167
|
//#endregion
|
|
168
168
|
export { constructPatterns as a, getAppGkmConfig as c, processConfig as d, workspaceConstructGlobs as f, stripPublicPrefix as g, getPublicEnvPrefix as h, assertNoMovedDeployKeys as i, getEndpointForStage as l, PUBLIC_ENV_PREFIXES as m, allConstructGlobs as n, defineWorkspace as o, wrapSingleAppAsWorkspace as p, appConstructGlobs as r, getAppBuildOrder as s, DokployRegistryMoved as t, normalizeWorkspace as u };
|
|
169
|
-
//# sourceMappingURL=index-
|
|
169
|
+
//# sourceMappingURL=index-DvoxuTqR.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DvoxuTqR.d.mts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC6ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBAgCX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;;;;;;;;cA8DU,6BAA6B;WACpB;EAArB,YAAqB;;;iBAUN,wBAAwB;iBAOxB,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBA+Ba,wBACf,WAAW;;;;;;;;;;;;iBAkBI,kBACf,WAAW,qBACX;;;;;;;iBAsBe,kBAAkB,WAAW;;iBAa7B,kBAAkB,QAAQ;;;;;iBAS1B,gBACf,WAAW,qBACX,kBACE;;;;;iBAgCa,iBAAiB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoD5B,oBACf;EACK;EAAmB,YAAY;eAEpC"}
|
package/dist/index.cjs
CHANGED
|
@@ -5,19 +5,19 @@ const require_run = require("./run-fVZ-rLnc.cjs");
|
|
|
5
5
|
const require_credentials = require("./credentials-BVs7mrtw.cjs");
|
|
6
6
|
const require_discover = require("./discover-B4VjaFJk.cjs");
|
|
7
7
|
const require_derive = require("./derive-DAbo49sm.cjs");
|
|
8
|
-
const require_workspace = require("./workspace-
|
|
8
|
+
const require_workspace = require("./workspace-vdrcRI-m.cjs");
|
|
9
9
|
const require_config = require("./config.cjs");
|
|
10
|
-
const require_state = require("./state-
|
|
11
|
-
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-
|
|
12
|
-
const require_sniffer = require("./sniffer-
|
|
10
|
+
const require_state = require("./state-CCuTJNRH.cjs");
|
|
11
|
+
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-DZZwHdDC.cjs");
|
|
12
|
+
const require_sniffer = require("./sniffer-DpHpFZBD.cjs");
|
|
13
13
|
const require_openapi = require("./openapi.cjs");
|
|
14
14
|
const require_appPorts = require("./appPorts-Cu79hJF6.cjs");
|
|
15
|
-
const require_ready = require("./ready-
|
|
15
|
+
const require_ready = require("./ready-Dp6arkI4.cjs");
|
|
16
16
|
const require_emit = require("./emit-Dmc1nvdS.cjs");
|
|
17
|
-
const require_deploy = require("./deploy-
|
|
18
|
-
const require_compose = require("./compose-
|
|
17
|
+
const require_deploy = require("./deploy-CZE0m6jd.cjs");
|
|
18
|
+
const require_compose = require("./compose-B-MME-4C.cjs");
|
|
19
19
|
const require_credentialSchemas = require("./credentialSchemas-BcNL1N5R.cjs");
|
|
20
|
-
const require_LocalStateStore = require("./LocalStateStore-
|
|
20
|
+
const require_LocalStateStore = require("./LocalStateStore-DTylG4T4.cjs");
|
|
21
21
|
const require_utils = require("./utils-D2Nk1Nv2.cjs");
|
|
22
22
|
let node_path = require("node:path");
|
|
23
23
|
let commander = require("commander");
|
|
@@ -33,10 +33,10 @@ let fast_glob = require("fast-glob");
|
|
|
33
33
|
fast_glob = require_rolldown_runtime.__toESM(fast_glob, 1);
|
|
34
34
|
let node_module = require("node:module");
|
|
35
35
|
let node_url = require("node:url");
|
|
36
|
+
let node_net = require("node:net");
|
|
36
37
|
let node_child_process = require("node:child_process");
|
|
37
38
|
let chokidar = require("chokidar");
|
|
38
39
|
chokidar = require_rolldown_runtime.__toESM(chokidar, 1);
|
|
39
|
-
let node_net = require("node:net");
|
|
40
40
|
let node_crypto = require("node:crypto");
|
|
41
41
|
let yaml = require("yaml");
|
|
42
42
|
let prompts = require("prompts");
|
|
@@ -53,7 +53,7 @@ let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions")
|
|
|
53
53
|
let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
|
|
54
54
|
let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
|
|
55
55
|
//#region package.json
|
|
56
|
-
var version = "10.0.0-alpha.
|
|
56
|
+
var version = "10.0.0-alpha.71";
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/prompt.ts
|
|
59
59
|
/**
|
|
@@ -136,7 +136,7 @@ const logger$8 = console;
|
|
|
136
136
|
* Validate Dokploy token by making a test API call
|
|
137
137
|
*/
|
|
138
138
|
async function validateDokployToken(endpoint, token) {
|
|
139
|
-
const { DokployApi } = await Promise.resolve().then(() => require("./sniffer-
|
|
139
|
+
const { DokployApi } = await Promise.resolve().then(() => require("./sniffer-DpHpFZBD.cjs")).then((n) => n.dokploy_api_exports);
|
|
140
140
|
return new DokployApi({
|
|
141
141
|
baseUrl: endpoint,
|
|
142
142
|
token
|
|
@@ -1624,8 +1624,7 @@ function normalizeProductionConfig(cliProduction) {
|
|
|
1624
1624
|
gracefulShutdown: true,
|
|
1625
1625
|
external: [],
|
|
1626
1626
|
subscribers: "include",
|
|
1627
|
-
openapi: false
|
|
1628
|
-
optimizedHandlers: true
|
|
1627
|
+
openapi: false
|
|
1629
1628
|
};
|
|
1630
1629
|
}
|
|
1631
1630
|
/** Read by the generated server: no subscriber is subscribed or polled. */
|
|
@@ -2042,9 +2041,9 @@ async function workspaceDevCommand(configured, options) {
|
|
|
2042
2041
|
for (const { id, port } of fakes) logger$5.log(`🎭 ${id} fake: http://localhost:${port}`);
|
|
2043
2042
|
logger$5.log(options.migrate || options.seed ? "🗄️ Migrating the databases" : "🗄️ Checking for pending migrations");
|
|
2044
2043
|
if (options.migrate || options.seed) {
|
|
2045
|
-
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-
|
|
2044
|
+
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs"));
|
|
2046
2045
|
await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
|
|
2047
|
-
} else await Promise.resolve().then(() => require("./migrate-
|
|
2046
|
+
} else await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
|
|
2048
2047
|
logger$5.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
|
|
2049
2048
|
});
|
|
2050
2049
|
const appUrls = {};
|
|
@@ -2707,7 +2706,7 @@ export async function setupCrons(
|
|
|
2707
2706
|
} catch (error) {
|
|
2708
2707
|
// An unrepresentable schedule is a build-time mistake, and failing the
|
|
2709
2708
|
// process for it would take the HTTP server down with it.
|
|
2710
|
-
logger.error({ error, cron: name }, 'Cron has no runnable schedule, skipping');
|
|
2709
|
+
logger.error({ err: error, cron: name }, 'Cron has no runnable schedule, skipping');
|
|
2711
2710
|
}
|
|
2712
2711
|
}
|
|
2713
2712
|
|
|
@@ -2718,7 +2717,7 @@ export async function setupCrons(
|
|
|
2718
2717
|
// \`handler\` a Cron does not have, so every firing logged a failure.
|
|
2719
2718
|
await runCron(entry.cron, serviceDiscovery);
|
|
2720
2719
|
} catch (error) {
|
|
2721
|
-
logger.error({ error, cron: entry.name }, 'Cron failed');
|
|
2720
|
+
logger.error({ err: error, cron: entry.name }, 'Cron failed');
|
|
2722
2721
|
}
|
|
2723
2722
|
};
|
|
2724
2723
|
|
|
@@ -3012,14 +3011,14 @@ export async function setupQueues(
|
|
|
3012
3011
|
db,
|
|
3013
3012
|
} as any);
|
|
3014
3013
|
} catch (error) {
|
|
3015
|
-
logger.error({ error, queue: queue.name }, 'Failed to process queue message');
|
|
3014
|
+
logger.error({ err: error, queue: queue.name }, 'Failed to process queue message');
|
|
3016
3015
|
// Rethrown so the transport keeps the message for a retry.
|
|
3017
3016
|
throw error;
|
|
3018
3017
|
}
|
|
3019
3018
|
});
|
|
3020
3019
|
logger.info({ queue: queue.name }, 'Queue consumer started polling');
|
|
3021
3020
|
} catch (error) {
|
|
3022
|
-
logger.error({ error, queue: queue.name }, 'Failed to set up queue consumer');
|
|
3021
|
+
logger.error({ err: error, queue: queue.name }, 'Failed to set up queue consumer');
|
|
3023
3022
|
}
|
|
3024
3023
|
}
|
|
3025
3024
|
|
|
@@ -3424,7 +3423,7 @@ async function buildApp(input) {
|
|
|
3424
3423
|
if (production?.bundle && !input.skipBundle) {
|
|
3425
3424
|
const outputDir = (0, node_path.join)(appRoot, ".gkm", "server");
|
|
3426
3425
|
const entryPoint = await writeSurfaceServer(outputDir, production);
|
|
3427
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
3426
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-CEaR6Dpb.cjs"));
|
|
3428
3427
|
await bundleServer({
|
|
3429
3428
|
entryPoint,
|
|
3430
3429
|
outputDir: (0, node_path.join)(outputDir, "dist"),
|
|
@@ -3562,7 +3561,7 @@ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointG
|
|
|
3562
3561
|
let masterKey;
|
|
3563
3562
|
if (context.production?.bundle && !skipBundle) {
|
|
3564
3563
|
logger$4.log(`\n📦 Bundling production server...`);
|
|
3565
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
3564
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-CEaR6Dpb.cjs"));
|
|
3566
3565
|
const allConstructs = [
|
|
3567
3566
|
...endpoints.map((e) => e.construct),
|
|
3568
3567
|
...functions.map((f) => f.construct),
|
|
@@ -3814,9 +3813,11 @@ async function composeCommand(options, deps = {}) {
|
|
|
3814
3813
|
const { workspace } = await require_config.loadWorkspaceConfig(cwd);
|
|
3815
3814
|
const { stage } = options;
|
|
3816
3815
|
if (options.down) {
|
|
3816
|
+
const override = require_compose.stackOverrideFile(workspace.root, stage);
|
|
3817
3817
|
const ref = {
|
|
3818
3818
|
project: require_compose.composeProject(require_state.deployIdentity(workspace, stage)),
|
|
3819
3819
|
file: (0, node_path.join)(workspace.root, require_compose.stackDir(stage), "docker-compose.yml"),
|
|
3820
|
+
...(0, node_fs.existsSync)(override) ? { overrides: [override] } : {},
|
|
3820
3821
|
cwd: workspace.root
|
|
3821
3822
|
};
|
|
3822
3823
|
await (deps.docker ?? require_compose.dockerCompose).down(ref);
|
|
@@ -5259,25 +5260,25 @@ function loadPackageJson() {
|
|
|
5259
5260
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
5260
5261
|
*/
|
|
5261
5262
|
const GEEKMIDAS_VERSIONS = {
|
|
5262
|
-
"@geekmidas/audit": "~10.0.0-alpha.
|
|
5263
|
-
"@geekmidas/auth": "~10.0.0-alpha.
|
|
5264
|
-
"@geekmidas/cache": "~10.0.0-alpha.
|
|
5265
|
-
"@geekmidas/client": "~10.0.0-alpha.
|
|
5266
|
-
"@geekmidas/cloud": "~10.0.0-alpha.
|
|
5267
|
-
"@geekmidas/constructs": "~10.0.0-alpha.
|
|
5268
|
-
"@geekmidas/db": "~10.0.0-alpha.
|
|
5269
|
-
"@geekmidas/emailkit": "~10.0.0-alpha.
|
|
5270
|
-
"@geekmidas/envkit": "~10.0.0-alpha.
|
|
5271
|
-
"@geekmidas/errors": "~10.0.0-alpha.
|
|
5272
|
-
"@geekmidas/events": "~10.0.0-alpha.
|
|
5273
|
-
"@geekmidas/logger": "~10.0.0-alpha.
|
|
5274
|
-
"@geekmidas/manifest": "~10.0.0-alpha.
|
|
5275
|
-
"@geekmidas/rate-limit": "~10.0.0-alpha.
|
|
5276
|
-
"@geekmidas/schema": "~10.0.0-alpha.
|
|
5277
|
-
"@geekmidas/services": "~10.0.0-alpha.
|
|
5278
|
-
"@geekmidas/storage": "~10.0.0-alpha.
|
|
5279
|
-
"@geekmidas/telescope": "~10.0.0-alpha.
|
|
5280
|
-
"@geekmidas/testkit": "~10.0.0-alpha.
|
|
5263
|
+
"@geekmidas/audit": "~10.0.0-alpha.71",
|
|
5264
|
+
"@geekmidas/auth": "~10.0.0-alpha.71",
|
|
5265
|
+
"@geekmidas/cache": "~10.0.0-alpha.71",
|
|
5266
|
+
"@geekmidas/client": "~10.0.0-alpha.71",
|
|
5267
|
+
"@geekmidas/cloud": "~10.0.0-alpha.71",
|
|
5268
|
+
"@geekmidas/constructs": "~10.0.0-alpha.71",
|
|
5269
|
+
"@geekmidas/db": "~10.0.0-alpha.71",
|
|
5270
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.71",
|
|
5271
|
+
"@geekmidas/envkit": "~10.0.0-alpha.71",
|
|
5272
|
+
"@geekmidas/errors": "~10.0.0-alpha.71",
|
|
5273
|
+
"@geekmidas/events": "~10.0.0-alpha.71",
|
|
5274
|
+
"@geekmidas/logger": "~10.0.0-alpha.71",
|
|
5275
|
+
"@geekmidas/manifest": "~10.0.0-alpha.71",
|
|
5276
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.71",
|
|
5277
|
+
"@geekmidas/schema": "~10.0.0-alpha.71",
|
|
5278
|
+
"@geekmidas/services": "~10.0.0-alpha.71",
|
|
5279
|
+
"@geekmidas/storage": "~10.0.0-alpha.71",
|
|
5280
|
+
"@geekmidas/telescope": "~10.0.0-alpha.71",
|
|
5281
|
+
"@geekmidas/testkit": "~10.0.0-alpha.71",
|
|
5281
5282
|
"@geekmidas/cli": `~${loadPackageJson().version}`
|
|
5282
5283
|
};
|
|
5283
5284
|
//#endregion
|
|
@@ -11067,7 +11068,7 @@ function testDatabases(reconciled) {
|
|
|
11067
11068
|
* starts without the reference data the app needs.
|
|
11068
11069
|
*/
|
|
11069
11070
|
async function migrateTestStage(workspace, env) {
|
|
11070
|
-
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-
|
|
11071
|
+
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs"));
|
|
11071
11072
|
const { discover } = await Promise.resolve().then(() => require("./discover-B4VjaFJk.cjs")).then((n) => n.discover_exports);
|
|
11072
11073
|
const sources = {};
|
|
11073
11074
|
const manifest = await discover({
|
|
@@ -11498,7 +11499,7 @@ program.command("migrate").description("Apply each database construct's migratio
|
|
|
11498
11499
|
try {
|
|
11499
11500
|
const globalOptions = program.opts();
|
|
11500
11501
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11501
|
-
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
11502
|
+
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs"));
|
|
11502
11503
|
await migrateCommand({
|
|
11503
11504
|
...options,
|
|
11504
11505
|
...construct ? { construct } : {}
|
|
@@ -11512,7 +11513,7 @@ program.command("seed").description("Migrate, then run each database construct's
|
|
|
11512
11513
|
try {
|
|
11513
11514
|
const globalOptions = program.opts();
|
|
11514
11515
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11515
|
-
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
11516
|
+
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs"));
|
|
11516
11517
|
await seedCommand({
|
|
11517
11518
|
...options,
|
|
11518
11519
|
...construct ? { construct } : {}
|
|
@@ -11526,7 +11527,7 @@ program.command("migration").description("Write a construct's next migration: an
|
|
|
11526
11527
|
try {
|
|
11527
11528
|
const globalOptions = program.opts();
|
|
11528
11529
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11529
|
-
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
11530
|
+
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-qKeGYq21.cjs"));
|
|
11530
11531
|
await migrationCommand({
|
|
11531
11532
|
construct,
|
|
11532
11533
|
...name ? { name } : {}
|
|
@@ -11620,7 +11621,7 @@ program.command("secrets:add").description("Build the keys a stage must be given
|
|
|
11620
11621
|
try {
|
|
11621
11622
|
const globalOptions = program.opts();
|
|
11622
11623
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11623
|
-
const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-
|
|
11624
|
+
const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-DeC2Kyyv.cjs"));
|
|
11624
11625
|
await secretsAddCommand(options);
|
|
11625
11626
|
} catch (error) {
|
|
11626
11627
|
console.error(formatError(error));
|
|
@@ -11631,7 +11632,7 @@ program.command("encryption:rotate").description("Add a new current key to an En
|
|
|
11631
11632
|
try {
|
|
11632
11633
|
const globalOptions = program.opts();
|
|
11633
11634
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11634
|
-
const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-
|
|
11635
|
+
const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-D05sNwED.cjs"));
|
|
11635
11636
|
await encryptionRotateCommand(construct, options);
|
|
11636
11637
|
} catch (error) {
|
|
11637
11638
|
console.error(formatError(error));
|
|
@@ -11642,7 +11643,7 @@ program.command("encryption:retire").description("Remove an old key from an Encr
|
|
|
11642
11643
|
try {
|
|
11643
11644
|
const globalOptions = program.opts();
|
|
11644
11645
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11645
|
-
const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-
|
|
11646
|
+
const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-D05sNwED.cjs"));
|
|
11646
11647
|
await encryptionRetireCommand(construct, key, options);
|
|
11647
11648
|
} catch (error) {
|
|
11648
11649
|
console.error(formatError(error));
|
|
@@ -11685,7 +11686,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
11685
11686
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11686
11687
|
const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
|
|
11687
11688
|
const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-CuCQBa5-.cjs"));
|
|
11688
|
-
const { secretsStoreFor } = await Promise.resolve().then(() => require("./state-
|
|
11689
|
+
const { secretsStoreFor } = await Promise.resolve().then(() => require("./state-CCuTJNRH.cjs")).then((n) => n.store_exports);
|
|
11689
11690
|
const { workspace } = await loadWorkspaceConfig();
|
|
11690
11691
|
const stage = options.stage ?? workspace.stages.local;
|
|
11691
11692
|
const store = await secretsStoreFor(workspace, stage);
|
|
@@ -11694,7 +11695,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
11694
11695
|
console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
11695
11696
|
process.exit(1);
|
|
11696
11697
|
}
|
|
11697
|
-
const { derivedContainers } = await Promise.resolve().then(() => require("./state-
|
|
11698
|
+
const { derivedContainers } = await Promise.resolve().then(() => require("./state-CCuTJNRH.cjs")).then((n) => n.workspace_exports);
|
|
11698
11699
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
|
|
11699
11700
|
if (!result) {
|
|
11700
11701
|
console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
|
|
@@ -11709,7 +11710,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
11709
11710
|
}
|
|
11710
11711
|
});
|
|
11711
11712
|
program.command("deploy").description("Deploy a stage through its target").option("--target <name>", "Deploy target: dokploy, compose, sst, or one named in deploy.targets (default: deploy.default)").option("--provider <provider>", "[DEPRECATED] Use --target instead").requiredOption("--stage <stage>", "Deployment stage (e.g., production, staging)").option("--tag <tag>", "Image tag (default: stage-timestamp; compose: the commit). Compose pulls a given tag").option("--skip-push", "Skip pushing image to registry").option("--skip-build", "Skip build step (use existing build)").option("--json", "Write events as JSON lines instead of progress; never prompts").option("--dry-run", "Show what would be created or reused; change, build and push nothing").option("--atomic", "If the release fails, roll back every app it released, not only the failed ones").option("--allow-dev-services <list>", "Server targets: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade").action(async (options) => {
|
|
11712
|
-
const { deployCli } = await Promise.resolve().then(() => require("./cli-
|
|
11713
|
+
const { deployCli } = await Promise.resolve().then(() => require("./cli-MMgBrHx7.cjs"));
|
|
11713
11714
|
const globalOptions = program.opts();
|
|
11714
11715
|
const code = await deployCli({
|
|
11715
11716
|
cwd: (0, node_path.resolve)(globalOptions.cwd ?? process.cwd()),
|
|
@@ -11726,7 +11727,7 @@ program.command("deploy").description("Deploy a stage through its target").optio
|
|
|
11726
11727
|
});
|
|
11727
11728
|
program.command("deploy:rollback").description("Put a stage's app back on its previous release (Dokploy): one app with --app, every app with --atomic").requiredOption("--stage <stage>", "A deployed stage").option("--app <app>", "The app to roll back").option("--atomic", "Roll back every app that has an earlier release").action(async (options) => {
|
|
11728
11729
|
try {
|
|
11729
|
-
const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-
|
|
11730
|
+
const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-DmcU-efZ.cjs")).then((n) => n.rollback_exports);
|
|
11730
11731
|
const { terminalCredentials } = await Promise.resolve().then(() => require("./terminal-CFO3xWoF.cjs"));
|
|
11731
11732
|
const globalOptions = program.opts();
|
|
11732
11733
|
await rollbackStage({
|
|
@@ -11762,7 +11763,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
|
|
|
11762
11763
|
try {
|
|
11763
11764
|
const globalOptions = program.opts();
|
|
11764
11765
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
11765
|
-
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-
|
|
11766
|
+
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BchWoiVx.cjs"));
|
|
11766
11767
|
await deployGithubCommand(options);
|
|
11767
11768
|
} catch (error) {
|
|
11768
11769
|
console.error(formatError(error));
|