@geekmidas/cli 10.0.0-alpha.61 → 10.0.0-alpha.63
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/README.md +2 -0
- package/dist/{HostingerProvider-DI_Pr2VE.mjs → HostingerProvider-DBBwpDjn.mjs} +2 -2
- package/dist/{HostingerProvider-DI_Pr2VE.mjs.map → HostingerProvider-DBBwpDjn.mjs.map} +1 -1
- package/dist/{HostingerProvider-CgDaD8VR.cjs → HostingerProvider-mJ7YruxH.cjs} +2 -2
- package/dist/{HostingerProvider-CgDaD8VR.cjs.map → HostingerProvider-mJ7YruxH.cjs.map} +1 -1
- package/dist/{LegacyStateStore-JbBVFp_2.cjs → LegacyStateStore-CP7SZwTP.cjs} +2 -2
- package/dist/{LegacyStateStore-JbBVFp_2.cjs.map → LegacyStateStore-CP7SZwTP.cjs.map} +1 -1
- package/dist/{LegacyStateStore-C7vFAxbu.mjs → LegacyStateStore-Q3GmKOdw.mjs} +2 -2
- package/dist/{LegacyStateStore-C7vFAxbu.mjs.map → LegacyStateStore-Q3GmKOdw.mjs.map} +1 -1
- package/dist/{LocalStateStore-DfUwQsL8.mjs → LocalStateStore-BGIXcrvX.mjs} +2 -2
- package/dist/{LocalStateStore-DfUwQsL8.mjs.map → LocalStateStore-BGIXcrvX.mjs.map} +1 -1
- package/dist/{LocalStateStore-DHj_-CQB.cjs → LocalStateStore-sS8mvLeq.cjs} +2 -2
- package/dist/{LocalStateStore-DHj_-CQB.cjs.map → LocalStateStore-sS8mvLeq.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs → OpenApiTsGenerator-CjHWFRDd.cjs} +2 -2
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs.map → OpenApiTsGenerator-CjHWFRDd.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs → OpenApiTsGenerator-CnAwhGxi.mjs} +2 -2
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs.map → OpenApiTsGenerator-CnAwhGxi.mjs.map} +1 -1
- package/dist/{S3StateStore-xqnpUrzy.cjs → S3StateStore-6jqITH2F.cjs} +2 -2
- package/dist/{S3StateStore-xqnpUrzy.cjs.map → S3StateStore-6jqITH2F.cjs.map} +1 -1
- package/dist/{S3StateStore-Dq6hHtzY.mjs → S3StateStore-D7l_lWJ3.mjs} +2 -2
- package/dist/{S3StateStore-Dq6hHtzY.mjs.map → S3StateStore-D7l_lWJ3.mjs.map} +1 -1
- package/dist/{SSMStateStore-5dBRwVlJ.cjs → SSMStateStore-B__F7IJa.cjs} +2 -2
- package/dist/{SSMStateStore-5dBRwVlJ.cjs.map → SSMStateStore-B__F7IJa.cjs.map} +1 -1
- package/dist/{SSMStateStore-SUmvAbLi.mjs → SSMStateStore-CAQDVpoc.mjs} +2 -2
- package/dist/{SSMStateStore-SUmvAbLi.mjs.map → SSMStateStore-CAQDVpoc.mjs.map} +1 -1
- package/dist/{bundler-DXATpO1T.cjs → bundler-DLfOn0ls.cjs} +3 -3
- package/dist/{bundler-DXATpO1T.cjs.map → bundler-DLfOn0ls.cjs.map} +1 -1
- package/dist/{bundler-B5VsKW-_.mjs → bundler-DyWI41Iy.mjs} +2 -2
- package/dist/{bundler-B5VsKW-_.mjs.map → bundler-DyWI41Iy.mjs.map} +1 -1
- package/dist/{cli-DQdrVkj2.cjs → cli-D-ZM-X2s.cjs} +12 -16
- package/dist/cli-D-ZM-X2s.cjs.map +1 -0
- package/dist/{cli-DEA_J3Sa.mjs → cli-PkVF28LM.mjs} +10 -14
- package/dist/cli-PkVF28LM.mjs.map +1 -0
- package/dist/{config-DXnkCEq0.cjs → config-BEJYKd4s.cjs} +132 -18
- package/dist/config-BEJYKd4s.cjs.map +1 -0
- package/dist/config-C2BUosLm.d.mts +256 -0
- package/dist/config-C2BUosLm.d.mts.map +1 -0
- package/dist/config-CemHVcIr.d.cts +256 -0
- package/dist/config-CemHVcIr.d.cts.map +1 -0
- package/dist/{config-C5-EEdmr.mjs → config-LKKCVCnC.mjs} +109 -19
- package/dist/config-LKKCVCnC.mjs.map +1 -0
- package/dist/config.cjs +6 -2
- package/dist/config.d.cts +4 -211
- package/dist/config.d.mts +4 -211
- package/dist/config.mjs +3 -3
- package/dist/define-CHBIEc5j.mjs +94 -0
- package/dist/define-CHBIEc5j.mjs.map +1 -0
- package/dist/define-Cv_QvDrg.cjs +141 -0
- package/dist/define-Cv_QvDrg.cjs.map +1 -0
- package/dist/deploy/public.cjs +174 -13
- package/dist/deploy/public.cjs.map +1 -0
- package/dist/deploy/public.d.cts +200 -292
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +200 -292
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +136 -3
- package/dist/deploy/public.mjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.cjs +54 -0
- package/dist/deploy/sniffer-envparser-worker.cjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.cts +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.mts +1 -0
- package/dist/deploy/sniffer-envparser-worker.mjs +55 -0
- package/dist/deploy/sniffer-envparser-worker.mjs.map +1 -0
- package/dist/{deploy-BbJdgQ2b.cjs → deploy-ABBI0lf1.cjs} +169 -561
- package/dist/deploy-ABBI0lf1.cjs.map +1 -0
- package/dist/deploy-BiMrP9i7.cjs +140 -0
- package/dist/deploy-BiMrP9i7.cjs.map +1 -0
- package/dist/{deploy-BJcLmVTc.mjs → deploy-CG8bfFij.mjs} +152 -532
- package/dist/deploy-CG8bfFij.mjs.map +1 -0
- package/dist/deploy-CGW-QY9D.mjs +135 -0
- package/dist/deploy-CGW-QY9D.mjs.map +1 -0
- package/dist/discover-B6yPpvRV.d.mts +99 -0
- package/dist/discover-B6yPpvRV.d.mts.map +1 -0
- package/dist/discover-B_IkPukx.d.cts +99 -0
- package/dist/discover-B_IkPukx.d.cts.map +1 -0
- package/dist/discover-BaT6bpnA.mjs +614 -0
- package/dist/discover-BaT6bpnA.mjs.map +1 -0
- package/dist/discover-C_6COHEv.cjs +729 -0
- package/dist/discover-C_6COHEv.cjs.map +1 -0
- package/dist/dokploy-CwdmlyQL.mjs +32 -0
- package/dist/dokploy-CwdmlyQL.mjs.map +1 -0
- package/dist/dokploy-QJxMhxdf.cjs +32 -0
- package/dist/dokploy-QJxMhxdf.cjs.map +1 -0
- package/dist/{encryption-DaA9gRXr.mjs → encryption-CbQG_ayW.mjs} +4 -4
- package/dist/{encryption-DaA9gRXr.mjs.map → encryption-CbQG_ayW.mjs.map} +1 -1
- package/dist/{encryption-ojzUo7-z.cjs → encryption-DXw3jj0c.cjs} +4 -4
- package/dist/{encryption-ojzUo7-z.cjs.map → encryption-DXw3jj0c.cjs.map} +1 -1
- package/dist/fakes-C9RiT6XG.mjs.map +1 -1
- package/dist/fakes-zW-jNAbQ.cjs.map +1 -1
- package/dist/{github-Cq57poPj.cjs → github-BH_mETav.cjs} +3 -3
- package/dist/{github-Cq57poPj.cjs.map → github-BH_mETav.cjs.map} +1 -1
- package/dist/{github-DmCj2u95.mjs → github-ciwbIwVa.mjs} +3 -3
- package/dist/{github-DmCj2u95.mjs.map → github-ciwbIwVa.mjs.map} +1 -1
- package/dist/{index-UiWCaGzU.d.cts → index-BtXDZQuF.d.cts} +2 -2
- package/dist/{index-Da1-oa9W.d.mts.map → index-BtXDZQuF.d.cts.map} +1 -1
- package/dist/{index-Da1-oa9W.d.mts → index-DrKzpHl-.d.mts} +2 -2
- package/dist/{index-UiWCaGzU.d.cts.map → index-DrKzpHl-.d.mts.map} +1 -1
- package/dist/index.cjs +60 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +57 -49
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-BScRpCEx.cjs → migrate-6oa9y_f2.cjs} +5 -5
- package/dist/{migrate-BScRpCEx.cjs.map → migrate-6oa9y_f2.cjs.map} +1 -1
- package/dist/{migrate-5_J5JySj.mjs → migrate-ImBKTBcW.mjs} +5 -5
- package/dist/{migrate-5_J5JySj.mjs.map → migrate-ImBKTBcW.mjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +3 -3
- package/dist/{ready-XlNx-Gbo.cjs → ready-BiG0rt4h.cjs} +3 -3
- package/dist/{ready-XlNx-Gbo.cjs.map → ready-BiG0rt4h.cjs.map} +1 -1
- package/dist/{ready-DQIy21W5.mjs → ready-Bpdnn2ON.mjs} +3 -3
- package/dist/{ready-DQIy21W5.mjs.map → ready-Bpdnn2ON.mjs.map} +1 -1
- package/dist/reconcile/public.cjs +1 -1
- package/dist/reconcile/public.d.cts +4 -77
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +4 -77
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +1 -1
- package/dist/resolve-B1T0hUaR.mjs +170 -0
- package/dist/resolve-B1T0hUaR.mjs.map +1 -0
- package/dist/resolve-xytBTtG4.cjs +217 -0
- package/dist/resolve-xytBTtG4.cjs.map +1 -0
- package/dist/runtime-CMwtq0AL.cjs +163 -0
- package/dist/runtime-CMwtq0AL.cjs.map +1 -0
- package/dist/runtime-CXPlkZzs.d.mts +90 -0
- package/dist/runtime-CXPlkZzs.d.mts.map +1 -0
- package/dist/runtime-DbakJS8u.mjs +134 -0
- package/dist/runtime-DbakJS8u.mjs.map +1 -0
- package/dist/runtime-Dn_n-29S.d.cts +90 -0
- package/dist/runtime-Dn_n-29S.d.cts.map +1 -0
- package/dist/sandbox/config-worker.cjs +43 -0
- package/dist/sandbox/config-worker.cjs.map +1 -0
- package/dist/sandbox/config-worker.d.cts +1 -0
- package/dist/sandbox/config-worker.d.mts +1 -0
- package/dist/sandbox/config-worker.mjs +44 -0
- package/dist/sandbox/config-worker.mjs.map +1 -0
- package/dist/sandbox/discover-worker.cjs +44 -0
- package/dist/sandbox/discover-worker.cjs.map +1 -0
- package/dist/sandbox/discover-worker.d.cts +1 -0
- package/dist/sandbox/discover-worker.d.mts +1 -0
- package/dist/sandbox/discover-worker.mjs +45 -0
- package/dist/sandbox/discover-worker.mjs.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.cts +126 -0
- package/dist/sandbox-M8UnLhXE.d.cts.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.mts +126 -0
- package/dist/sandbox-M8UnLhXE.d.mts.map +1 -0
- package/dist/{workspace-Bp1xVaOz.mjs → schemas-Ckm_aBnF.cjs} +264 -969
- package/dist/schemas-Ckm_aBnF.cjs.map +1 -0
- package/dist/{workspace-B64Xk1Mb.cjs → schemas-D2LCF689.mjs} +195 -1155
- package/dist/schemas-D2LCF689.mjs.map +1 -0
- package/dist/{sniffer-CQmJnNJM.cjs → sniffer-D_SYc_pO.cjs} +379 -214
- package/dist/sniffer-D_SYc_pO.cjs.map +1 -0
- package/dist/{sniffer-bdleks5l.mjs → sniffer-aO_-s5vq.mjs} +346 -211
- package/dist/sniffer-aO_-s5vq.mjs.map +1 -0
- package/dist/target/public.cjs +15 -0
- package/dist/target/public.d.cts +28 -0
- package/dist/target/public.d.cts.map +1 -0
- package/dist/target/public.d.mts +28 -0
- package/dist/target/public.d.mts.map +1 -0
- package/dist/target/public.mjs +4 -0
- package/dist/terminal-D0f1u0LG.cjs +576 -0
- package/dist/terminal-D0f1u0LG.cjs.map +1 -0
- package/dist/terminal-gMxAo9Dj.mjs +517 -0
- package/dist/terminal-gMxAo9Dj.mjs.map +1 -0
- package/dist/{types-efNLu9xu.d.cts → types-CfLKGfC_.d.mts} +624 -34
- package/dist/types-CfLKGfC_.d.mts.map +1 -0
- package/dist/{types-Bp1mVxG0.d.mts → types-DIA7Li-J.d.cts} +626 -34
- package/dist/types-DIA7Li-J.d.cts.map +1 -0
- package/dist/vitest.cjs +2 -2
- package/dist/vitest.mjs +2 -2
- package/dist/workerRuntime-BXfhbe13.cjs +108 -0
- package/dist/workerRuntime-BXfhbe13.cjs.map +1 -0
- package/dist/workerRuntime-CsOyBRx2.mjs +79 -0
- package/dist/workerRuntime-CsOyBRx2.mjs.map +1 -0
- 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-Dh7rr7l4.mjs +1024 -0
- package/dist/workspace-Dh7rr7l4.mjs.map +1 -0
- package/dist/workspace-Kl4NG9IH.cjs +1196 -0
- package/dist/workspace-Kl4NG9IH.cjs.map +1 -0
- package/package.json +23 -13
- package/dist/cli-DEA_J3Sa.mjs.map +0 -1
- package/dist/cli-DQdrVkj2.cjs.map +0 -1
- package/dist/config-C5-EEdmr.mjs.map +0 -1
- package/dist/config-DXnkCEq0.cjs.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.mts.map +0 -1
- package/dist/deploy-BJcLmVTc.mjs.map +0 -1
- package/dist/deploy-BbJdgQ2b.cjs.map +0 -1
- package/dist/discover-Bc-4eA_p.cjs +0 -299
- package/dist/discover-Bc-4eA_p.cjs.map +0 -1
- package/dist/discover-FrYvzkeC.mjs +0 -262
- package/dist/discover-FrYvzkeC.mjs.map +0 -1
- package/dist/sniffer-CQmJnNJM.cjs.map +0 -1
- package/dist/sniffer-bdleks5l.mjs.map +0 -1
- package/dist/types-Bp1mVxG0.d.mts.map +0 -1
- package/dist/types-efNLu9xu.d.cts.map +0 -1
- package/dist/workspace-B64Xk1Mb.cjs.map +0 -1
- package/dist/workspace-Bp1xVaOz.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-Cq57poPj.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
|
+
{"version":3,"file":"github-BH_mETav.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,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { D as assertDeployedStage } from "./workspace-
|
|
1
|
+
import { p as loadWorkspaceConfig } from "./config-LKKCVCnC.mjs";
|
|
2
|
+
import { D as assertDeployedStage } from "./workspace-Dh7rr7l4.mjs";
|
|
3
3
|
import { a as getKeyPath, c as readKey, n as secretsStoreFor, o as keystoreProject, t as isRemoteStore } from "./store-BS8A7NcA.mjs";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { AttachRolePolicyCommand, CreateOpenIDConnectProviderCommand, CreateRoleCommand, GetRoleCommand, IAMClient, ListOpenIDConnectProvidersCommand, UpdateAssumeRolePolicyCommand } from "@aws-sdk/client-iam";
|
|
@@ -210,4 +210,4 @@ var SsoSessionExpired = class extends Error {
|
|
|
210
210
|
//#endregion
|
|
211
211
|
export { deployGithubCommand };
|
|
212
212
|
|
|
213
|
-
//# sourceMappingURL=github-
|
|
213
|
+
//# sourceMappingURL=github-ciwbIwVa.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-DmCj2u95.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":";;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,SAAS;AAEf,MAAM,mBAAmB;AACzB,MAAM,WAAW;AAsBjB,MAAM,aAAiB,MAAM,UAC5B,aAAa,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,IAAI,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,IAAI,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,IAAI,eAAe,EAAE,UAAU,KAAK,CAAC,CAAC;EACtE,MAAM,IAAI,KACT,IAAI,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,IAAI,kBAAkB;GACrB,UAAU;GACV,0BAA0B;GAC1B,aAAa;GAEb,oBAAoB;EACrB,CAAC,CACF;EACA,MAAM,KAAM;CACb;CAGA,MAAM,IAAI,KACT,IAAI,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,IAAI,UAAU,MAAM;AAC5B;AAEA,eAAsB,oBACrB,SACA,OAAmD,CAAC,GACN;CAC9C,MAAM,KAAK,KAAK,MAAM;CACtB,MAAM,EAAE,cAAc,MAAM,oBAAoB,KAAK,GAAG;CACxD,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,MAAM,QAAQ,QAAQ,OAAO,gBAAgB,SAAS,CAAC;CACnE,MAAM,UAAU,WAAW,QAAQ,OAAO,gBAAgB,SAAS,CAAC;CACpE,MAAM,SAAS,QAAQ;CAGvB,MAAM,SAAS,cAAc,WAAW,QAAQ,KAAK;CAGrD,MAAM,QAAQ,MAAM,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
|
+
{"version":3,"file":"github-ciwbIwVa.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 { C as WorkspaceConfig, D as Framework, _ as LoadedConfig, a as Routes, b as NormalizedWorkspace, g as InferredWorkspaceConfig, l as AppsRecord, r as GkmConfig, w as WorkspaceInput } from "./types-
|
|
1
|
+
import { C as WorkspaceConfig, D as Framework, _ as LoadedConfig, a as Routes, b as NormalizedWorkspace, g as InferredWorkspaceConfig, l as AppsRecord, r as GkmConfig, w as WorkspaceInput } from "./types-DIA7Li-J.cjs";
|
|
2
2
|
//#region src/workspace/publicEnv.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* All public env-var prefixes the toolbox understands.
|
|
@@ -153,4 +153,4 @@ declare function getEndpointForStage(dokployConfig: {
|
|
|
153
153
|
} | undefined, stage: string): string | undefined;
|
|
154
154
|
//#endregion
|
|
155
155
|
export { getAppBuildOrder as a, normalizeWorkspace as c, wrapSingleAppAsWorkspace as d, PUBLIC_ENV_PREFIXES as f, defineWorkspace as i, processConfig as l, stripPublicPrefix as m, appConstructGlobs as n, getAppGkmConfig as o, getPublicEnvPrefix as p, constructPatterns as r, getEndpointForStage as s, allConstructGlobs as t, workspaceConstructGlobs as u };
|
|
156
|
-
//# sourceMappingURL=index-
|
|
156
|
+
//# sourceMappingURL=index-BtXDZQuF.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-BtXDZQuF.d.cts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC2ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBA8BX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;iBAuDa,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBA6Ba,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 { C as WorkspaceConfig, D as Framework, _ as LoadedConfig, a as Routes, b as NormalizedWorkspace, g as InferredWorkspaceConfig, l as AppsRecord, r as GkmConfig, w as WorkspaceInput } from "./types-
|
|
1
|
+
import { C as WorkspaceConfig, D as Framework, _ as LoadedConfig, a as Routes, b as NormalizedWorkspace, g as InferredWorkspaceConfig, l as AppsRecord, r as GkmConfig, w as WorkspaceInput } from "./types-CfLKGfC_.mjs";
|
|
2
2
|
//#region src/workspace/publicEnv.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* All public env-var prefixes the toolbox understands.
|
|
@@ -153,4 +153,4 @@ declare function getEndpointForStage(dokployConfig: {
|
|
|
153
153
|
} | undefined, stage: string): string | undefined;
|
|
154
154
|
//#endregion
|
|
155
155
|
export { getAppBuildOrder as a, normalizeWorkspace as c, wrapSingleAppAsWorkspace as d, PUBLIC_ENV_PREFIXES as f, defineWorkspace as i, processConfig as l, stripPublicPrefix as m, appConstructGlobs as n, getAppGkmConfig as o, getPublicEnvPrefix as p, constructPatterns as r, getEndpointForStage as s, allConstructGlobs as t, workspaceConstructGlobs as u };
|
|
156
|
-
//# sourceMappingURL=index-
|
|
156
|
+
//# sourceMappingURL=index-DrKzpHl-.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DrKzpHl-.d.mts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC2ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBA8BX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;iBAuDa,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBA6Ba,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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
4
|
-
const require_sniffer = require("./sniffer-
|
|
5
|
-
const require_discover = require("./discover-
|
|
6
|
-
const require_config = require("./config-
|
|
7
|
-
const require_workspace = require("./workspace-
|
|
4
|
+
const require_sniffer = require("./sniffer-D_SYc_pO.cjs");
|
|
5
|
+
const require_discover = require("./discover-C_6COHEv.cjs");
|
|
6
|
+
const require_config = require("./config-BEJYKd4s.cjs");
|
|
7
|
+
const require_workspace = require("./workspace-Kl4NG9IH.cjs");
|
|
8
8
|
const require_storage = require("./storage-CSGoC3bK.cjs");
|
|
9
9
|
const require_store = require("./store-KvNQwYaB.cjs");
|
|
10
|
-
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-
|
|
10
|
+
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-CjHWFRDd.cjs");
|
|
11
11
|
const require_openapi = require("./openapi.cjs");
|
|
12
12
|
const require_fakes = require("./fakes-zW-jNAbQ.cjs");
|
|
13
13
|
const require_appPorts = require("./appPorts-Cu79hJF6.cjs");
|
|
14
|
-
const require_ready = require("./ready-
|
|
14
|
+
const require_ready = require("./ready-BiG0rt4h.cjs");
|
|
15
15
|
const require_emit = require("./emit-Dmc1nvdS.cjs");
|
|
16
|
-
const require_LocalStateStore = require("./LocalStateStore-
|
|
16
|
+
const require_LocalStateStore = require("./LocalStateStore-sS8mvLeq.cjs");
|
|
17
17
|
let node_path = require("node:path");
|
|
18
18
|
let commander = require("commander");
|
|
19
19
|
let node_fs = require("node:fs");
|
|
@@ -23,13 +23,13 @@ let node_util = require("node:util");
|
|
|
23
23
|
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
24
24
|
let fast_glob = require("fast-glob");
|
|
25
25
|
fast_glob = require_rolldown_runtime.__toESM(fast_glob, 1);
|
|
26
|
-
let node_child_process = require("node:child_process");
|
|
27
26
|
let node_module = require("node:module");
|
|
27
|
+
let node_url = require("node:url");
|
|
28
|
+
let node_child_process = require("node:child_process");
|
|
28
29
|
let chokidar = require("chokidar");
|
|
29
30
|
chokidar = require_rolldown_runtime.__toESM(chokidar, 1);
|
|
30
31
|
let node_net = require("node:net");
|
|
31
32
|
let node_crypto = require("node:crypto");
|
|
32
|
-
let node_url = require("node:url");
|
|
33
33
|
let pg = require("pg");
|
|
34
34
|
pg = require_rolldown_runtime.__toESM(pg, 1);
|
|
35
35
|
let yaml = require("yaml");
|
|
@@ -47,7 +47,7 @@ let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions")
|
|
|
47
47
|
let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
|
|
48
48
|
let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
|
|
49
49
|
//#region package.json
|
|
50
|
-
var version = "10.0.0-alpha.
|
|
50
|
+
var version = "10.0.0-alpha.63";
|
|
51
51
|
//#endregion
|
|
52
52
|
//#region src/trust/index.ts
|
|
53
53
|
/**
|
|
@@ -1851,9 +1851,9 @@ async function workspaceDevCommand(configured, options) {
|
|
|
1851
1851
|
for (const { id, port } of fakes) logger$6.log(`🎭 ${id} fake: http://localhost:${port}`);
|
|
1852
1852
|
logger$6.log(options.migrate || options.seed ? "🗄️ Migrating the databases" : "🗄️ Checking for pending migrations");
|
|
1853
1853
|
if (options.migrate || options.seed) {
|
|
1854
|
-
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-
|
|
1854
|
+
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs"));
|
|
1855
1855
|
await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
|
|
1856
|
-
} else await Promise.resolve().then(() => require("./migrate-
|
|
1856
|
+
} else await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
|
|
1857
1857
|
logger$6.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
|
|
1858
1858
|
});
|
|
1859
1859
|
const appUrls = {};
|
|
@@ -2068,7 +2068,7 @@ var EntryRunner = class {
|
|
|
2068
2068
|
const env = {
|
|
2069
2069
|
...process.env,
|
|
2070
2070
|
PORT: String(this.port),
|
|
2071
|
-
NODE_OPTIONS:
|
|
2071
|
+
NODE_OPTIONS: require_discover.withOwningTsconfigJsx(process.env.NODE_OPTIONS)
|
|
2072
2072
|
};
|
|
2073
2073
|
this.childProcess = (0, node_child_process.spawn)(...tsxCommand((0, node_path.dirname)(this.wrapperPath), [this.wrapperPath]), {
|
|
2074
2074
|
stdio: "inherit",
|
|
@@ -2338,7 +2338,7 @@ var DevServer = class {
|
|
|
2338
2338
|
...process.env,
|
|
2339
2339
|
NODE_ENV: "development",
|
|
2340
2340
|
GKM_DEV_PID: String(process.pid),
|
|
2341
|
-
NODE_OPTIONS:
|
|
2341
|
+
NODE_OPTIONS: require_discover.withOwningTsconfigJsx(process.env.NODE_OPTIONS)
|
|
2342
2342
|
},
|
|
2343
2343
|
detached: true
|
|
2344
2344
|
});
|
|
@@ -3233,7 +3233,7 @@ async function buildApp(input) {
|
|
|
3233
3233
|
if (production?.bundle && !input.skipBundle) {
|
|
3234
3234
|
const outputDir = (0, node_path.join)(appRoot, ".gkm", "server");
|
|
3235
3235
|
const entryPoint = await writeSurfaceServer(outputDir, production);
|
|
3236
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
3236
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-DLfOn0ls.cjs"));
|
|
3237
3237
|
await bundleServer({
|
|
3238
3238
|
entryPoint,
|
|
3239
3239
|
outputDir: (0, node_path.join)(outputDir, "dist"),
|
|
@@ -3371,7 +3371,7 @@ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointG
|
|
|
3371
3371
|
let masterKey;
|
|
3372
3372
|
if (context.production?.bundle && !skipBundle) {
|
|
3373
3373
|
logger$5.log(`\n📦 Bundling production server...`);
|
|
3374
|
-
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-
|
|
3374
|
+
const { bundleServer } = await Promise.resolve().then(() => require("./bundler-DLfOn0ls.cjs"));
|
|
3375
3375
|
const allConstructs = [
|
|
3376
3376
|
...endpoints.map((e) => e.construct),
|
|
3377
3377
|
...functions.map((f) => f.construct),
|
|
@@ -3535,13 +3535,20 @@ async function workspaceBuildCommand(workspace, options) {
|
|
|
3535
3535
|
if (filters.length > 0) {
|
|
3536
3536
|
logger$5.log(`\n📦 Using ${pm} with Turbo for the other apps...\n`);
|
|
3537
3537
|
logger$5.log(`Running: ${[turboBin, ...turboArgs].join(" ")}`);
|
|
3538
|
-
|
|
3538
|
+
const sandbox = options.sandbox ?? new require_sniffer.LocalSandbox({
|
|
3539
|
+
root: workspace.root,
|
|
3540
|
+
passEnv: ["TURBO_TOKEN"]
|
|
3541
|
+
});
|
|
3542
|
+
const built = await sandbox.exec(turboBin, turboArgs, {
|
|
3539
3543
|
cwd: workspace.root,
|
|
3540
3544
|
env: {
|
|
3541
|
-
...
|
|
3545
|
+
...sandbox.env,
|
|
3542
3546
|
NODE_ENV: options.production ? "production" : "development"
|
|
3543
|
-
}
|
|
3547
|
+
},
|
|
3548
|
+
timeoutMs: require_sniffer.DEFAULT_TIMEOUT_MS,
|
|
3549
|
+
output: "inherit"
|
|
3544
3550
|
});
|
|
3551
|
+
if (built.exitCode !== 0) throw new require_sniffer.CommandFailed(turboBin, turboArgs, built.exitCode, built.signal);
|
|
3545
3552
|
}
|
|
3546
3553
|
for (const [appName, app] of apps) {
|
|
3547
3554
|
const outputPath = getAppOutputPath(workspace, appName, app);
|
|
@@ -5181,7 +5188,7 @@ async function deployInitCommand(options) {
|
|
|
5181
5188
|
logger$3.log(`\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);
|
|
5182
5189
|
logger$3.log(`\n📝 Next steps:`);
|
|
5183
5190
|
logger$3.log(` 1. Initialize secrets: gkm secrets:init --stage production`);
|
|
5184
|
-
logger$3.log(` 2. Deploy: gkm deploy --
|
|
5191
|
+
logger$3.log(` 2. Deploy: gkm deploy --stage production`);
|
|
5185
5192
|
return config;
|
|
5186
5193
|
}
|
|
5187
5194
|
/**
|
|
@@ -6479,25 +6486,25 @@ function loadPackageJson() {
|
|
|
6479
6486
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
6480
6487
|
*/
|
|
6481
6488
|
const GEEKMIDAS_VERSIONS = {
|
|
6482
|
-
"@geekmidas/audit": "~10.0.0-alpha.
|
|
6483
|
-
"@geekmidas/auth": "~10.0.0-alpha.
|
|
6484
|
-
"@geekmidas/cache": "~10.0.0-alpha.
|
|
6485
|
-
"@geekmidas/client": "~10.0.0-alpha.
|
|
6486
|
-
"@geekmidas/cloud": "~10.0.0-alpha.
|
|
6487
|
-
"@geekmidas/constructs": "~10.0.0-alpha.
|
|
6488
|
-
"@geekmidas/db": "~10.0.0-alpha.
|
|
6489
|
-
"@geekmidas/emailkit": "~10.0.0-alpha.
|
|
6490
|
-
"@geekmidas/envkit": "~10.0.0-alpha.
|
|
6491
|
-
"@geekmidas/errors": "~10.0.0-alpha.
|
|
6492
|
-
"@geekmidas/events": "~10.0.0-alpha.
|
|
6493
|
-
"@geekmidas/logger": "~10.0.0-alpha.
|
|
6494
|
-
"@geekmidas/manifest": "~10.0.0-alpha.
|
|
6495
|
-
"@geekmidas/rate-limit": "~10.0.0-alpha.
|
|
6496
|
-
"@geekmidas/schema": "~10.0.0-alpha.
|
|
6497
|
-
"@geekmidas/services": "~10.0.0-alpha.
|
|
6498
|
-
"@geekmidas/storage": "~10.0.0-alpha.
|
|
6499
|
-
"@geekmidas/telescope": "~10.0.0-alpha.
|
|
6500
|
-
"@geekmidas/testkit": "~10.0.0-alpha.
|
|
6489
|
+
"@geekmidas/audit": "~10.0.0-alpha.63",
|
|
6490
|
+
"@geekmidas/auth": "~10.0.0-alpha.63",
|
|
6491
|
+
"@geekmidas/cache": "~10.0.0-alpha.63",
|
|
6492
|
+
"@geekmidas/client": "~10.0.0-alpha.63",
|
|
6493
|
+
"@geekmidas/cloud": "~10.0.0-alpha.63",
|
|
6494
|
+
"@geekmidas/constructs": "~10.0.0-alpha.63",
|
|
6495
|
+
"@geekmidas/db": "~10.0.0-alpha.63",
|
|
6496
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.63",
|
|
6497
|
+
"@geekmidas/envkit": "~10.0.0-alpha.63",
|
|
6498
|
+
"@geekmidas/errors": "~10.0.0-alpha.63",
|
|
6499
|
+
"@geekmidas/events": "~10.0.0-alpha.63",
|
|
6500
|
+
"@geekmidas/logger": "~10.0.0-alpha.63",
|
|
6501
|
+
"@geekmidas/manifest": "~10.0.0-alpha.63",
|
|
6502
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.63",
|
|
6503
|
+
"@geekmidas/schema": "~10.0.0-alpha.63",
|
|
6504
|
+
"@geekmidas/services": "~10.0.0-alpha.63",
|
|
6505
|
+
"@geekmidas/storage": "~10.0.0-alpha.63",
|
|
6506
|
+
"@geekmidas/telescope": "~10.0.0-alpha.63",
|
|
6507
|
+
"@geekmidas/testkit": "~10.0.0-alpha.63",
|
|
6501
6508
|
"@geekmidas/cli": `~${loadPackageJson().version}`
|
|
6502
6509
|
};
|
|
6503
6510
|
//#endregion
|
|
@@ -8027,7 +8034,7 @@ const perStage = (options, command) => Object.fromEntries(options.stages.deploye
|
|
|
8027
8034
|
function deployPackage(options) {
|
|
8028
8035
|
switch (options.deployTarget) {
|
|
8029
8036
|
case "dokploy": return {
|
|
8030
|
-
scripts: perStage(options, (stage) => `gkm deploy --
|
|
8037
|
+
scripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),
|
|
8031
8038
|
dependencies: {},
|
|
8032
8039
|
devDependencies: {}
|
|
8033
8040
|
};
|
|
@@ -12398,8 +12405,8 @@ function testDatabases(reconciled) {
|
|
|
12398
12405
|
* starts without the reference data the app needs.
|
|
12399
12406
|
*/
|
|
12400
12407
|
async function migrateTestStage(workspace, env) {
|
|
12401
|
-
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-
|
|
12402
|
-
const { discover } = await Promise.resolve().then(() => require("./discover-
|
|
12408
|
+
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs"));
|
|
12409
|
+
const { discover } = await Promise.resolve().then(() => require("./discover-C_6COHEv.cjs")).then((n) => n.discover_exports);
|
|
12403
12410
|
const sources = {};
|
|
12404
12411
|
const manifest = await discover({
|
|
12405
12412
|
patterns: require_sniffer.constructGlobs(workspace),
|
|
@@ -12829,7 +12836,7 @@ program.command("migrate").description("Apply each database construct's migratio
|
|
|
12829
12836
|
try {
|
|
12830
12837
|
const globalOptions = program.opts();
|
|
12831
12838
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
12832
|
-
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
12839
|
+
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs"));
|
|
12833
12840
|
await migrateCommand({
|
|
12834
12841
|
...options,
|
|
12835
12842
|
...construct ? { construct } : {}
|
|
@@ -12843,7 +12850,7 @@ program.command("seed").description("Migrate, then run each database construct's
|
|
|
12843
12850
|
try {
|
|
12844
12851
|
const globalOptions = program.opts();
|
|
12845
12852
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
12846
|
-
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
12853
|
+
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs"));
|
|
12847
12854
|
await seedCommand({
|
|
12848
12855
|
...options,
|
|
12849
12856
|
...construct ? { construct } : {}
|
|
@@ -12857,7 +12864,7 @@ program.command("migration").description("Write a construct's next migration: an
|
|
|
12857
12864
|
try {
|
|
12858
12865
|
const globalOptions = program.opts();
|
|
12859
12866
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
12860
|
-
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
12867
|
+
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-6oa9y_f2.cjs"));
|
|
12861
12868
|
await migrationCommand({
|
|
12862
12869
|
construct,
|
|
12863
12870
|
...name ? { name } : {}
|
|
@@ -12965,7 +12972,7 @@ program.command("encryption:rotate").description("Add a new current key to an En
|
|
|
12965
12972
|
try {
|
|
12966
12973
|
const globalOptions = program.opts();
|
|
12967
12974
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
12968
|
-
const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-
|
|
12975
|
+
const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-DXw3jj0c.cjs"));
|
|
12969
12976
|
await encryptionRotateCommand(construct, options);
|
|
12970
12977
|
} catch (error) {
|
|
12971
12978
|
console.error(formatError(error));
|
|
@@ -12976,7 +12983,7 @@ program.command("encryption:retire").description("Remove an old key from an Encr
|
|
|
12976
12983
|
try {
|
|
12977
12984
|
const globalOptions = program.opts();
|
|
12978
12985
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
12979
|
-
const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-
|
|
12986
|
+
const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-DXw3jj0c.cjs"));
|
|
12980
12987
|
await encryptionRetireCommand(construct, key, options);
|
|
12981
12988
|
} catch (error) {
|
|
12982
12989
|
console.error(formatError(error));
|
|
@@ -13028,7 +13035,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
13028
13035
|
console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
13029
13036
|
process.exit(1);
|
|
13030
13037
|
}
|
|
13031
|
-
const { derivedContainers } = await Promise.resolve().then(() => require("./sniffer-
|
|
13038
|
+
const { derivedContainers } = await Promise.resolve().then(() => require("./sniffer-D_SYc_pO.cjs")).then((n) => n.workspace_exports);
|
|
13032
13039
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
|
|
13033
13040
|
if (!result) {
|
|
13034
13041
|
console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
|
|
@@ -13042,12 +13049,13 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
13042
13049
|
process.exit(1);
|
|
13043
13050
|
}
|
|
13044
13051
|
});
|
|
13045
|
-
program.command("deploy").description("Deploy
|
|
13046
|
-
const { deployCli } = await Promise.resolve().then(() => require("./cli-
|
|
13052
|
+
program.command("deploy").description("Deploy a stage through its target").option("--target <name>", "Deploy target: dokploy, 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)").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").action(async (options) => {
|
|
13053
|
+
const { deployCli } = await Promise.resolve().then(() => require("./cli-D-ZM-X2s.cjs"));
|
|
13047
13054
|
const globalOptions = program.opts();
|
|
13048
13055
|
const code = await deployCli({
|
|
13049
13056
|
cwd: (0, node_path.resolve)(globalOptions.cwd ?? process.cwd()),
|
|
13050
|
-
|
|
13057
|
+
...options.target ? { target: options.target } : {},
|
|
13058
|
+
...options.provider ? { provider: options.provider } : {},
|
|
13051
13059
|
stage: options.stage,
|
|
13052
13060
|
...options.tag ? { tag: options.tag } : {},
|
|
13053
13061
|
...options.json ? { json: true } : {},
|
|
@@ -13075,7 +13083,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
|
|
|
13075
13083
|
try {
|
|
13076
13084
|
const globalOptions = program.opts();
|
|
13077
13085
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
13078
|
-
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-
|
|
13086
|
+
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BH_mETav.cjs"));
|
|
13079
13087
|
await deployGithubCommand(options);
|
|
13080
13088
|
} catch (error) {
|
|
13081
13089
|
console.error(formatError(error));
|