@geekmidas/cli 10.0.0-alpha.74 → 10.0.0-alpha.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/{LegacyStateStore-D_78eaHM.cjs → LegacyStateStore-DwngfJxr.cjs} +2 -2
  2. package/dist/{LegacyStateStore-D_78eaHM.cjs.map → LegacyStateStore-DwngfJxr.cjs.map} +1 -1
  3. package/dist/{LegacyStateStore-DTo7z924.mjs → LegacyStateStore-dyq07_Ir.mjs} +2 -2
  4. package/dist/{LegacyStateStore-DTo7z924.mjs.map → LegacyStateStore-dyq07_Ir.mjs.map} +1 -1
  5. package/dist/{LocalStateStore-BhrlQIXD.cjs → LocalStateStore-B0NCde8Z.cjs} +2 -2
  6. package/dist/{LocalStateStore-BhrlQIXD.cjs.map → LocalStateStore-B0NCde8Z.cjs.map} +1 -1
  7. package/dist/{LocalStateStore-CNjgkRk4.mjs → LocalStateStore-DLxCCatI.mjs} +2 -2
  8. package/dist/{LocalStateStore-CNjgkRk4.mjs.map → LocalStateStore-DLxCCatI.mjs.map} +1 -1
  9. package/dist/{S3StateStore-oCxRs6HM.cjs → S3StateStore-BOenb-3o.cjs} +2 -2
  10. package/dist/{S3StateStore-oCxRs6HM.cjs.map → S3StateStore-BOenb-3o.cjs.map} +1 -1
  11. package/dist/{S3StateStore-g2P7T_Mo.mjs → S3StateStore-CGK_4hlo.mjs} +2 -2
  12. package/dist/{S3StateStore-g2P7T_Mo.mjs.map → S3StateStore-CGK_4hlo.mjs.map} +1 -1
  13. package/dist/{SSMStateStore-CYenunmK.mjs → SSMStateStore-B_5_RqY-.mjs} +2 -2
  14. package/dist/{SSMStateStore-CYenunmK.mjs.map → SSMStateStore-B_5_RqY-.mjs.map} +1 -1
  15. package/dist/{SSMStateStore-DXp0m7XI.cjs → SSMStateStore-DYeD__7p.cjs} +2 -2
  16. package/dist/{SSMStateStore-DXp0m7XI.cjs.map → SSMStateStore-DYeD__7p.cjs.map} +1 -1
  17. package/dist/{add-BTH7WaH3.mjs → add-B7IMXzou.mjs} +3 -3
  18. package/dist/{add-BTH7WaH3.mjs.map → add-B7IMXzou.mjs.map} +1 -1
  19. package/dist/{add-Djrr12Xc.cjs → add-j2yI3cbS.cjs} +3 -3
  20. package/dist/{add-Djrr12Xc.cjs.map → add-j2yI3cbS.cjs.map} +1 -1
  21. package/dist/{aws-DojzQnLd.mjs → aws-Bja4zGSs.mjs} +13 -9
  22. package/dist/aws-Bja4zGSs.mjs.map +1 -0
  23. package/dist/{aws-DkHdTV-p.cjs → aws-CQAuluiu.cjs} +13 -9
  24. package/dist/aws-CQAuluiu.cjs.map +1 -0
  25. package/dist/awsStore-7VmS_cZR.cjs +54 -0
  26. package/dist/awsStore-7VmS_cZR.cjs.map +1 -0
  27. package/dist/awsStore-B529csle.mjs +43 -0
  28. package/dist/awsStore-B529csle.mjs.map +1 -0
  29. package/dist/{bundler-utHuESvL.cjs → bundler-Cf6OgaOe.cjs} +5 -5
  30. package/dist/bundler-Cf6OgaOe.cjs.map +1 -0
  31. package/dist/{bundler-BUojOkof.mjs → bundler-DO6bHhnb.mjs} +5 -5
  32. package/dist/bundler-DO6bHhnb.mjs.map +1 -0
  33. package/dist/{cli-CyYceKTS.mjs → cli-BCPOHmg9.mjs} +3 -3
  34. package/dist/{cli-CyYceKTS.mjs.map → cli-BCPOHmg9.mjs.map} +1 -1
  35. package/dist/{cli-Bx0sUzxH.cjs → cli-CNanUB7a.cjs} +3 -3
  36. package/dist/{cli-Bx0sUzxH.cjs.map → cli-CNanUB7a.cjs.map} +1 -1
  37. package/dist/{compose-DZp8DJ0A.mjs → compose-Dq4VCtu5.mjs} +221 -153
  38. package/dist/compose-Dq4VCtu5.mjs.map +1 -0
  39. package/dist/{compose-iuw8wfHk.cjs → compose-h_6oNnHC.cjs} +243 -151
  40. package/dist/compose-h_6oNnHC.cjs.map +1 -0
  41. package/dist/{config-B38YWicj.d.cts → config-CWyhLSY1.d.cts} +3 -3
  42. package/dist/{config-B38YWicj.d.cts.map → config-CWyhLSY1.d.cts.map} +1 -1
  43. package/dist/{config-DA0kRTQe.d.mts → config-CqAvPP-f.d.mts} +3 -3
  44. package/dist/{config-DA0kRTQe.d.mts.map → config-CqAvPP-f.d.mts.map} +1 -1
  45. package/dist/config.cjs +1 -1
  46. package/dist/config.d.cts +3 -3
  47. package/dist/config.d.mts +3 -3
  48. package/dist/config.mjs +1 -1
  49. package/dist/deploy/public.cjs +7 -6
  50. package/dist/deploy/public.d.cts +14 -3
  51. package/dist/deploy/public.d.cts.map +1 -1
  52. package/dist/deploy/public.d.mts +14 -3
  53. package/dist/deploy/public.d.mts.map +1 -1
  54. package/dist/deploy/public.mjs +7 -7
  55. package/dist/{deploy-eWorhvQp.cjs → deploy-CT3R9de9.cjs} +27 -5
  56. package/dist/deploy-CT3R9de9.cjs.map +1 -0
  57. package/dist/{deploy-C17K7Imy.mjs → deploy-CVXEx7Nm.mjs} +22 -6
  58. package/dist/deploy-CVXEx7Nm.mjs.map +1 -0
  59. package/dist/{dokploy-DKa49Nqm.mjs → dokploy-CYm2ozFs.mjs} +2 -2
  60. package/dist/{dokploy-DKa49Nqm.mjs.map → dokploy-CYm2ozFs.mjs.map} +1 -1
  61. package/dist/{dokploy-DKzcI-RL.cjs → dokploy-eSGmlhhj.cjs} +2 -2
  62. package/dist/{dokploy-DKzcI-RL.cjs.map → dokploy-eSGmlhhj.cjs.map} +1 -1
  63. package/dist/{encryption-sTMz3aWi.mjs → encryption-DC0rsR1W.mjs} +3 -3
  64. package/dist/{encryption-sTMz3aWi.mjs.map → encryption-DC0rsR1W.mjs.map} +1 -1
  65. package/dist/{encryption-DSkJdoyk.cjs → encryption-vS3Qzw73.cjs} +3 -3
  66. package/dist/{encryption-DSkJdoyk.cjs.map → encryption-vS3Qzw73.cjs.map} +1 -1
  67. package/dist/{engine-B1b4I34Z.mjs → engine-BOO5TWZd.mjs} +193 -5
  68. package/dist/engine-BOO5TWZd.mjs.map +1 -0
  69. package/dist/{engine-Bh76sAHy.cjs → engine-C0N2d1i5.cjs} +196 -8
  70. package/dist/engine-C0N2d1i5.cjs.map +1 -0
  71. package/dist/{github-C9ODoyZU.mjs → github-CEaFDL6t.mjs} +6 -6
  72. package/dist/github-CEaFDL6t.mjs.map +1 -0
  73. package/dist/{github-BvN3CfxM.cjs → github-ClkdCOL9.cjs} +6 -6
  74. package/dist/github-ClkdCOL9.cjs.map +1 -0
  75. package/dist/{index-B-1lLGzy.d.mts → index-Ccu0f_2m.d.cts} +2 -2
  76. package/dist/{index-B-1lLGzy.d.mts.map → index-Ccu0f_2m.d.cts.map} +1 -1
  77. package/dist/{index-vMidfqhU.d.cts → index-DOxmDKqv.d.mts} +2 -2
  78. package/dist/{index-vMidfqhU.d.cts.map → index-DOxmDKqv.d.mts.map} +1 -1
  79. package/dist/index.cjs +106 -52
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.mjs +105 -51
  82. package/dist/index.mjs.map +1 -1
  83. package/dist/migrate-BRbYtFXG.cjs +93 -0
  84. package/dist/migrate-BRbYtFXG.cjs.map +1 -0
  85. package/dist/migrate-D3NAT7Ns.mjs +93 -0
  86. package/dist/migrate-D3NAT7Ns.mjs.map +1 -0
  87. package/dist/{migrate-B0FCZNkp.cjs → migrate-D5_-ylI1.cjs} +3 -3
  88. package/dist/{migrate-B0FCZNkp.cjs.map → migrate-D5_-ylI1.cjs.map} +1 -1
  89. package/dist/{migrate-CTtJhGV9.mjs → migrate-DrO2p9Rl.mjs} +3 -3
  90. package/dist/{migrate-CTtJhGV9.mjs.map → migrate-DrO2p9Rl.mjs.map} +1 -1
  91. package/dist/openapi.cjs +16 -6
  92. package/dist/openapi.cjs.map +1 -1
  93. package/dist/openapi.d.cts +1 -1
  94. package/dist/openapi.d.cts.map +1 -1
  95. package/dist/openapi.d.mts +1 -1
  96. package/dist/openapi.d.mts.map +1 -1
  97. package/dist/openapi.mjs +16 -6
  98. package/dist/openapi.mjs.map +1 -1
  99. package/dist/reconcile/public.d.cts +1 -1
  100. package/dist/reconcile/public.d.mts +1 -1
  101. package/dist/{resolve-DSAXj_47.mjs → resolve-C1muFos5.mjs} +3 -3
  102. package/dist/{resolve-DSAXj_47.mjs.map → resolve-C1muFos5.mjs.map} +1 -1
  103. package/dist/{resolve-D_BU-wKA.cjs → resolve-Fa1Ii0BK.cjs} +3 -3
  104. package/dist/{resolve-D_BU-wKA.cjs.map → resolve-Fa1Ii0BK.cjs.map} +1 -1
  105. package/dist/{rollback-DJy3t696.cjs → rollback-C9N5lKVf.cjs} +5 -5
  106. package/dist/{rollback-DJy3t696.cjs.map → rollback-C9N5lKVf.cjs.map} +1 -1
  107. package/dist/{rollback-CWYTUhfW.mjs → rollback-DeQzbRqM.mjs} +5 -5
  108. package/dist/{rollback-CWYTUhfW.mjs.map → rollback-DeQzbRqM.mjs.map} +1 -1
  109. package/dist/{runtime-BzZD5HHi.d.cts → runtime-BSvzPqXW.d.mts} +2 -2
  110. package/dist/{runtime-BzZD5HHi.d.cts.map → runtime-BSvzPqXW.d.mts.map} +1 -1
  111. package/dist/{runtime-Cm6J6L7n.d.mts → runtime-Cm7QA53H.d.cts} +2 -2
  112. package/dist/{runtime-Cm6J6L7n.d.mts.map → runtime-Cm7QA53H.d.cts.map} +1 -1
  113. package/dist/secretsManager-DUXW3fQt.cjs +70 -0
  114. package/dist/secretsManager-DUXW3fQt.cjs.map +1 -0
  115. package/dist/secretsManager-Ti0oZwsS.mjs +70 -0
  116. package/dist/secretsManager-Ti0oZwsS.mjs.map +1 -0
  117. package/dist/{sniffer-BFmdZpZ2.mjs → sniffer-DR8AlRCk.mjs} +67 -15
  118. package/dist/sniffer-DR8AlRCk.mjs.map +1 -0
  119. package/dist/{sniffer-C-T7dSMN.cjs → sniffer-Y6GQOCXB.cjs} +83 -13
  120. package/dist/sniffer-Y6GQOCXB.cjs.map +1 -0
  121. package/dist/{state-DCwRWyh-.cjs → state-C2qi0iQw.cjs} +241 -334
  122. package/dist/state-C2qi0iQw.cjs.map +1 -0
  123. package/dist/{state-DpkxSwzI.mjs → state-CUecOCNJ.mjs} +213 -306
  124. package/dist/state-CUecOCNJ.mjs.map +1 -0
  125. package/dist/target/public.cjs +1 -1
  126. package/dist/target/public.d.cts +2 -2
  127. package/dist/target/public.d.mts +2 -2
  128. package/dist/target/public.mjs +1 -1
  129. package/dist/{types-TzCChNrA.d.cts → types-BdptGBFS.d.cts} +59 -6
  130. package/dist/types-BdptGBFS.d.cts.map +1 -0
  131. package/dist/{types-Dp9lgx_S.d.mts → types-OxE0OAn2.d.mts} +59 -6
  132. package/dist/types-OxE0OAn2.d.mts.map +1 -0
  133. package/dist/workspace/index.cjs +1 -1
  134. package/dist/workspace/index.d.cts +2 -2
  135. package/dist/workspace/index.d.mts +2 -2
  136. package/dist/workspace/index.mjs +1 -1
  137. package/dist/{workspace-vdrcRI-m.cjs → workspace-DOm81oUo.cjs} +54 -1
  138. package/dist/workspace-DOm81oUo.cjs.map +1 -0
  139. package/dist/{workspace-C7NqCsQF.mjs → workspace-QUTqYmVy.mjs} +43 -2
  140. package/dist/workspace-QUTqYmVy.mjs.map +1 -0
  141. package/package.json +18 -17
  142. package/dist/aws-DkHdTV-p.cjs.map +0 -1
  143. package/dist/aws-DojzQnLd.mjs.map +0 -1
  144. package/dist/bundler-BUojOkof.mjs.map +0 -1
  145. package/dist/bundler-utHuESvL.cjs.map +0 -1
  146. package/dist/compose-DZp8DJ0A.mjs.map +0 -1
  147. package/dist/compose-iuw8wfHk.cjs.map +0 -1
  148. package/dist/deploy-C17K7Imy.mjs.map +0 -1
  149. package/dist/deploy-eWorhvQp.cjs.map +0 -1
  150. package/dist/engine-B1b4I34Z.mjs.map +0 -1
  151. package/dist/engine-Bh76sAHy.cjs.map +0 -1
  152. package/dist/github-BvN3CfxM.cjs.map +0 -1
  153. package/dist/github-C9ODoyZU.mjs.map +0 -1
  154. package/dist/sniffer-BFmdZpZ2.mjs.map +0 -1
  155. package/dist/sniffer-C-T7dSMN.cjs.map +0 -1
  156. package/dist/state-DCwRWyh-.cjs.map +0 -1
  157. package/dist/state-DpkxSwzI.mjs.map +0 -1
  158. package/dist/types-Dp9lgx_S.d.mts.map +0 -1
  159. package/dist/types-TzCChNrA.d.cts.map +0 -1
  160. package/dist/workspace-C7NqCsQF.mjs.map +0 -1
  161. package/dist/workspace-vdrcRI-m.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
- import { k as assertDeployedStage } from "./workspace-C7NqCsQF.mjs";
1
+ import { k as assertDeployedStage } from "./workspace-QUTqYmVy.mjs";
2
2
  import { loadWorkspaceConfig } from "./config.mjs";
3
- import { Gt as isRemoteStore, Kt as secretsStoreFor, Qt as readKey, Xt as keystoreProject, Yt as getKeyPath } from "./state-DpkxSwzI.mjs";
3
+ import { Gt as secretsStoreFor, Qt as readKey, Wt as isRemoteStore, Xt as keystoreProject, Yt as getKeyPath } from "./state-CUecOCNJ.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
@@ -18,9 +18,9 @@ import { AttachRolePolicyCommand, CreateOpenIDConnectProviderCommand, CreateRole
18
18
  * GitHub it creates that environment and gives it what the generated deploy
19
19
  * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in
20
20
  * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to
21
- * SSM the deploy job pulls them with the role instead, so no key is handed to
22
- * GitHub, and this pushes the stage's local secrets to SSM in the same account,
23
- * with the same profile. Re-running it converges rather than duplicating.
21
+ * SSM or Secrets Manager the deploy job reads them with the role instead, so
22
+ * no key is handed to GitHub, and this checks the stage's store in the same
23
+ * account, with the same profile. Re-running it converges rather than duplicating.
24
24
  */
25
25
  const logger = console;
26
26
  const GITHUB_OIDC_HOST = "token.actions.githubusercontent.com";
@@ -210,4 +210,4 @@ var SsoSessionExpired = class extends Error {
210
210
  //#endregion
211
211
  export { deployGithubCommand };
212
212
 
213
- //# sourceMappingURL=github-C9ODoyZU.mjs.map
213
+ //# sourceMappingURL=github-CEaFDL6t.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-CEaFDL6t.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 or Secrets Manager the deploy job reads them with the role instead, so\n * no key is handed to GitHub, and this checks the stage's store in the same\n * account, 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,6 +1,6 @@
1
- const require_workspace = require("./workspace-vdrcRI-m.cjs");
1
+ const require_workspace = require("./workspace-DOm81oUo.cjs");
2
2
  const require_config = require("./config.cjs");
3
- const require_state = require("./state-DCwRWyh-.cjs");
3
+ const require_state = require("./state-C2qi0iQw.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
@@ -18,9 +18,9 @@ let _aws_sdk_client_iam = require("@aws-sdk/client-iam");
18
18
  * GitHub it creates that environment and gives it what the generated deploy
19
19
  * workflow reads: `AWS_ROLE_ARN`, and — when the stage's secrets are kept in
20
20
  * the local file — its key as `GKM_SECRETS_KEY`. With `secrets.store` set to
21
- * SSM the deploy job pulls them with the role instead, so no key is handed to
22
- * GitHub, and this pushes the stage's local secrets to SSM in the same account,
23
- * with the same profile. Re-running it converges rather than duplicating.
21
+ * SSM or Secrets Manager the deploy job reads them with the role instead, so
22
+ * no key is handed to GitHub, and this checks the stage's store in the same
23
+ * account, with the same profile. Re-running it converges rather than duplicating.
24
24
  */
25
25
  const logger = console;
26
26
  const GITHUB_OIDC_HOST = "token.actions.githubusercontent.com";
@@ -210,4 +210,4 @@ var SsoSessionExpired = class extends Error {
210
210
  //#endregion
211
211
  exports.deployGithubCommand = deployGithubCommand;
212
212
 
213
- //# sourceMappingURL=github-BvN3CfxM.cjs.map
213
+ //# sourceMappingURL=github-ClkdCOL9.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-ClkdCOL9.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 or Secrets Manager the deploy job reads them with the role instead, so\n * no key is handed to GitHub, and this checks the stage's store in the same\n * account, 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 { 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-Dp9lgx_S.mjs";
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-BdptGBFS.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-B-1lLGzy.d.mts.map
169
+ //# sourceMappingURL=index-Ccu0f_2m.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-B-1lLGzy.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"}
1
+ {"version":3,"file":"index-Ccu0f_2m.d.cts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC8ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBAiCX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;;;;;;;;cA8DU,6BAA6B;WACpB;EAArB,YAAqB;;;iBAUN,wBAAwB;iBAOxB,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBAgCa,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 { 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-TzCChNrA.cjs";
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-OxE0OAn2.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-vMidfqhU.d.cts.map
169
+ //# sourceMappingURL=index-DOxmDKqv.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-vMidfqhU.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
+ {"version":3,"file":"index-DOxmDKqv.d.mts","names":[],"sources":["../src/workspace/publicEnv.ts","../src/workspace/index.ts"],"mappings":";;;;;;;;;cASa;;;;;;;;;;;;;;;iBAoBG,mBAAmB,YAAY;;;;;iBAoB/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBC8ElB,sBAAsB,cAAc,YACnD,QAAQ,eAAe,SACrB,wBAAwB;;;;iBAiCX,mBACf,QAAQ,iBACR,cACE;;;;;iBAgDa,yBACf,QAAQ,WACR,cACE;;;;;;;;;;;;cA8DU,6BAA6B;WACpB;EAArB,YAAqB;;;iBAUN,wBAAwB;iBAOxB,cACf,QAAQ,YAAY,iBACpB,cACE;;;;;;;iBAgCa,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,20 +5,20 @@ const require_run = require("./run-fVZ-rLnc.cjs");
5
5
  const require_credentials = require("./credentials-BVs7mrtw.cjs");
6
6
  const require_discover = require("./discover-D1It5r_h.cjs");
7
7
  const require_derive = require("./derive-DAbo49sm.cjs");
8
- const require_workspace = require("./workspace-vdrcRI-m.cjs");
8
+ const require_workspace = require("./workspace-DOm81oUo.cjs");
9
9
  const require_config = require("./config.cjs");
10
- const require_state = require("./state-DCwRWyh-.cjs");
10
+ const require_state = require("./state-C2qi0iQw.cjs");
11
11
  const require_EndpointGenerator = require("./EndpointGenerator-CP6sBvQV.cjs");
12
- const require_sniffer = require("./sniffer-C-T7dSMN.cjs");
13
12
  const require_openapi = require("./openapi.cjs");
14
13
  const require_SubscriberGenerator = require("./SubscriberGenerator-CajwOa5W.cjs");
15
14
  const require_appPorts = require("./appPorts-Cu79hJF6.cjs");
16
15
  const require_drivers = require("./drivers-BdvtCKc7.cjs");
17
16
  const require_emit = require("./emit-Dmc1nvdS.cjs");
18
- const require_deploy = require("./deploy-eWorhvQp.cjs");
19
- const require_compose = require("./compose-iuw8wfHk.cjs");
17
+ const require_sniffer = require("./sniffer-Y6GQOCXB.cjs");
18
+ const require_deploy = require("./deploy-CT3R9de9.cjs");
19
+ const require_compose = require("./compose-h_6oNnHC.cjs");
20
20
  const require_credentialSchemas = require("./credentialSchemas-DCR4Wd1W.cjs");
21
- const require_LocalStateStore = require("./LocalStateStore-BhrlQIXD.cjs");
21
+ const require_LocalStateStore = require("./LocalStateStore-B0NCde8Z.cjs");
22
22
  const require_utils = require("./utils-D2Nk1Nv2.cjs");
23
23
  const require_ready = require("./ready-BB9xS4S9.cjs");
24
24
  let node_path = require("node:path");
@@ -53,7 +53,7 @@ crypto = require_rolldown_runtime.__toESM(crypto, 1);
53
53
  let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions");
54
54
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
55
55
  //#region package.json
56
- var version = "10.0.0-alpha.74";
56
+ var version = "10.0.0-alpha.76";
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-C-T7dSMN.cjs")).then((n) => n.dokploy_api_exports);
139
+ const { DokployApi } = await Promise.resolve().then(() => require("./sniffer-Y6GQOCXB.cjs")).then((n) => n.dokploy_api_exports);
140
140
  return new DokployApi({
141
141
  baseUrl: endpoint,
142
142
  token
@@ -1533,10 +1533,10 @@ async function execCommand(commandArgs, options = {}) {
1533
1533
  if (!commandArgs[0]) throw new NoCommandSpecified();
1534
1534
  const defaultEnv = require_state.loadEnvFiles(".env");
1535
1535
  if (defaultEnv.loaded.length > 0) logger$6.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1536
- const { credentials, secretsJsonPath, appName } = await require_state.prepareEntryCredentials({ cwd });
1536
+ const { credentials, secretsJsonPath, appName } = require_state.isImageBuild() ? await imageBuildEntry(cwd) : await require_state.prepareEntryCredentials({ cwd });
1537
1537
  if (appName) logger$6.log(`📦 App: ${appName}`);
1538
1538
  const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
1539
- if (secretCount > 0) logger$6.log(`🔐 Loaded ${secretCount} secret(s)`);
1539
+ if (secretCount > 0 && !require_state.isImageBuild()) logger$6.log(`🔐 Loaded ${secretCount} secret(s)`);
1540
1540
  const preloadDir = (0, node_path.join)(cwd, ".gkm");
1541
1541
  await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
1542
1542
  const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.mjs");
@@ -1562,6 +1562,23 @@ async function execCommand(commandArgs, options = {}) {
1562
1562
  });
1563
1563
  if (exitCode !== 0) process.exit(exitCode);
1564
1564
  }
1565
+ /**
1566
+ * `gkm exec` inside an image build: the public values the Dockerfile's build
1567
+ * args set, written where the preload reads them. No workspace is loaded, no
1568
+ * secret read and no address resolved.
1569
+ */
1570
+ async function imageBuildEntry(cwd) {
1571
+ const credentials = require_state.imageBuildCredentials();
1572
+ logger$6.log(`🐳 Image build: ${Object.keys(credentials).length} public value(s) from the build args`);
1573
+ const dir = (0, node_path.join)(cwd, ".gkm");
1574
+ await (0, node_fs_promises.mkdir)(dir, { recursive: true });
1575
+ const secretsJsonPath = (0, node_path.join)(dir, "image-build-env.json");
1576
+ await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(credentials, null, 2));
1577
+ return {
1578
+ credentials,
1579
+ secretsJsonPath
1580
+ };
1581
+ }
1565
1582
  //#endregion
1566
1583
  //#region src/dev/index.ts
1567
1584
  const logger$5 = console;
@@ -2042,9 +2059,9 @@ async function workspaceDevCommand(configured, options) {
2042
2059
  for (const { id, port } of fakes) logger$5.log(`🎭 ${id} fake: http://localhost:${port}`);
2043
2060
  logger$5.log(options.migrate || options.seed ? "🗄️ Migrating the databases" : "🗄️ Checking for pending migrations");
2044
2061
  if (options.migrate || options.seed) {
2045
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs"));
2062
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs"));
2046
2063
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
2047
- } else await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
2064
+ } else await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
2048
2065
  logger$5.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
2049
2066
  });
2050
2067
  const appUrls = {};
@@ -3052,7 +3069,7 @@ async function buildApp(input) {
3052
3069
  if (production?.bundle && !input.skipBundle) {
3053
3070
  const outputDir = (0, node_path.join)(appRoot, ".gkm", "server");
3054
3071
  const entryPoint = await writeSurfaceServer(outputDir, production);
3055
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-utHuESvL.cjs"));
3072
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-Cf6OgaOe.cjs"));
3056
3073
  await bundleServer({
3057
3074
  entryPoint,
3058
3075
  outputDir: (0, node_path.join)(outputDir, "dist"),
@@ -3176,7 +3193,7 @@ async function buildWorkers(input) {
3176
3193
  });
3177
3194
  logger$4.log(`Generated worker ${worker.id}: ${crons.length} crons, ${queues.length} queues, ${subscribers.length} subscribers`);
3178
3195
  if (!input.bundle) continue;
3179
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-utHuESvL.cjs"));
3196
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-Cf6OgaOe.cjs"));
3180
3197
  const outfile = require_state.workerBundleName(worker.id);
3181
3198
  await bundleServer({
3182
3199
  entryPoint,
@@ -3246,7 +3263,7 @@ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointG
3246
3263
  let masterKey;
3247
3264
  if (context.production?.bundle && !skipBundle) {
3248
3265
  logger$4.log(`\n📦 Bundling production server...`);
3249
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-utHuESvL.cjs"));
3266
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-Cf6OgaOe.cjs"));
3250
3267
  const allConstructs = [
3251
3268
  ...endpoints.map((e) => e.construct),
3252
3269
  ...functions.map((f) => f.construct),
@@ -3269,7 +3286,7 @@ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointG
3269
3286
  await (0, node_fs_promises.writeFile)(keyPath, `${masterKey}\n`, { mode: 384 });
3270
3287
  await (0, node_fs_promises.chmod)(keyPath, 384);
3271
3288
  logger$4.log(`\n🔐 Secrets encrypted for deployment`);
3272
- logger$4.log(` Run with GKM_MASTER_KEY set to the key in ${(0, node_path.relative)(appRoot, keyPath)} (fingerprint ${require_state.keyFingerprint(masterKey)})`);
3289
+ logger$4.log(` Run with GKM_MASTER_KEY set to the key in ${(0, node_path.relative)(appRoot, keyPath)} (fingerprint ${require_sniffer.keyFingerprint(masterKey)})`);
3273
3290
  }
3274
3291
  }
3275
3292
  return {
@@ -3490,9 +3507,16 @@ var ComposeModeConflict = class extends Error {
3490
3507
  this.name = "ComposeModeConflict";
3491
3508
  }
3492
3509
  };
3510
+ /** Each pushed image as `<ref>@sha256:…`, by app. */
3511
+ function pushedDigests(run) {
3512
+ return Object.fromEntries(Object.entries(run.images).filter(([, image]) => image.digest).sort(([a], [b]) => a.localeCompare(b)).map(([app, image]) => [app, require_compose.pinnedRef(image.ref, image.digest)]));
3513
+ }
3493
3514
  /** `gkm compose`. */
3494
3515
  async function composeCommand(options, deps = {}) {
3495
3516
  if (options.build && options.pull) throw new ComposeModeConflict();
3517
+ if (options.push && !options.build) throw new require_compose.ComposePushNeedsBuild();
3518
+ const pulls = !options.build && (options.pull || options.tag !== void 0);
3519
+ if (options.digestsFile && !options.push && !pulls) throw new require_compose.ComposePinNeedsPull();
3496
3520
  const allowDevServices = require_state.parseDevServices(options.allowDevServices);
3497
3521
  const cwd = (0, node_path.resolve)(options.cwd ?? process.cwd());
3498
3522
  const { workspace } = await require_config.loadWorkspaceConfig(cwd);
@@ -3512,6 +3536,10 @@ async function composeCommand(options, deps = {}) {
3512
3536
  let finished;
3513
3537
  const mode = options.build ? "build" : options.pull ? "pull" : void 0;
3514
3538
  const tag = options.tag ?? (options.pull ? "latest" : void 0);
3539
+ const pin = options.digestsFile && pulls ? {
3540
+ file: options.digestsFile,
3541
+ digests: require_compose.parseDigests(options.digestsFile, await (0, node_fs_promises.readFile)((0, node_path.resolve)(cwd, options.digestsFile), "utf-8"))
3542
+ } : void 0;
3515
3543
  const result = await require_deploy.deploy({
3516
3544
  cwd,
3517
3545
  stage,
@@ -3519,12 +3547,15 @@ async function composeCommand(options, deps = {}) {
3519
3547
  targets: { compose: require_compose.composeTarget({
3520
3548
  ...deps,
3521
3549
  ...mode ? { mode } : {},
3550
+ ...options.push ? { push: true } : {},
3551
+ ...pin ? { pin } : {},
3522
3552
  report: (done) => {
3523
3553
  finished = done;
3524
3554
  }
3525
3555
  }) },
3526
3556
  ...tag ? { tag } : {},
3527
3557
  ...options.dryRun ? { dryRun: true } : {},
3558
+ ...options.push ? { buildOnly: true } : {},
3528
3559
  ...allowDevServices.length > 0 ? { allowDevServices } : {},
3529
3560
  logger: {
3530
3561
  info: (message) => console.log(message),
@@ -3533,6 +3564,17 @@ async function composeCommand(options, deps = {}) {
3533
3564
  }
3534
3565
  }).result;
3535
3566
  if (!finished) return void 0;
3567
+ if (options.push && !options.dryRun) {
3568
+ const digests = pushedDigests(finished);
3569
+ console.log(`\n✅ Pushed ${Object.keys(digests).length} image(s):`);
3570
+ for (const [app, ref] of Object.entries(digests)) console.log(` ${app.padEnd(12)} ${ref}`);
3571
+ if (options.digestsFile) {
3572
+ const file = (0, node_path.resolve)(cwd, options.digestsFile);
3573
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(file), { recursive: true });
3574
+ await (0, node_fs_promises.writeFile)(file, `${JSON.stringify(digests, null, 2)}\n`);
3575
+ console.log(`\n📝 Wrote the digests to ${options.digestsFile}`);
3576
+ }
3577
+ }
3536
3578
  return {
3537
3579
  stack: finished.stack,
3538
3580
  files: finished.files,
@@ -4945,25 +4987,25 @@ function loadPackageJson() {
4945
4987
  * Run: pnpm --filter @geekmidas/cli sync-versions
4946
4988
  */
4947
4989
  const GEEKMIDAS_VERSIONS = {
4948
- "@geekmidas/audit": "~10.0.0-alpha.74",
4949
- "@geekmidas/auth": "~10.0.0-alpha.74",
4950
- "@geekmidas/cache": "~10.0.0-alpha.74",
4951
- "@geekmidas/client": "~10.0.0-alpha.74",
4952
- "@geekmidas/cloud": "~10.0.0-alpha.74",
4953
- "@geekmidas/constructs": "~10.0.0-alpha.74",
4954
- "@geekmidas/db": "~10.0.0-alpha.74",
4955
- "@geekmidas/emailkit": "~10.0.0-alpha.74",
4956
- "@geekmidas/envkit": "~10.0.0-alpha.74",
4957
- "@geekmidas/errors": "~10.0.0-alpha.74",
4958
- "@geekmidas/events": "~10.0.0-alpha.74",
4959
- "@geekmidas/logger": "~10.0.0-alpha.74",
4960
- "@geekmidas/manifest": "~10.0.0-alpha.74",
4961
- "@geekmidas/rate-limit": "~10.0.0-alpha.74",
4962
- "@geekmidas/schema": "~10.0.0-alpha.74",
4963
- "@geekmidas/services": "~10.0.0-alpha.74",
4964
- "@geekmidas/storage": "~10.0.0-alpha.74",
4965
- "@geekmidas/telescope": "~10.0.0-alpha.74",
4966
- "@geekmidas/testkit": "~10.0.0-alpha.74",
4990
+ "@geekmidas/audit": "~10.0.0-alpha.76",
4991
+ "@geekmidas/auth": "~10.0.0-alpha.76",
4992
+ "@geekmidas/cache": "~10.0.0-alpha.76",
4993
+ "@geekmidas/client": "~10.0.0-alpha.76",
4994
+ "@geekmidas/cloud": "~10.0.0-alpha.76",
4995
+ "@geekmidas/constructs": "~10.0.0-alpha.76",
4996
+ "@geekmidas/db": "~10.0.0-alpha.76",
4997
+ "@geekmidas/emailkit": "~10.0.0-alpha.76",
4998
+ "@geekmidas/envkit": "~10.0.0-alpha.76",
4999
+ "@geekmidas/errors": "~10.0.0-alpha.76",
5000
+ "@geekmidas/events": "~10.0.0-alpha.76",
5001
+ "@geekmidas/logger": "~10.0.0-alpha.76",
5002
+ "@geekmidas/manifest": "~10.0.0-alpha.76",
5003
+ "@geekmidas/rate-limit": "~10.0.0-alpha.76",
5004
+ "@geekmidas/schema": "~10.0.0-alpha.76",
5005
+ "@geekmidas/services": "~10.0.0-alpha.76",
5006
+ "@geekmidas/storage": "~10.0.0-alpha.76",
5007
+ "@geekmidas/telescope": "~10.0.0-alpha.76",
5008
+ "@geekmidas/testkit": "~10.0.0-alpha.76",
4967
5009
  "@geekmidas/cli": `~${loadPackageJson().version}`
4968
5010
  };
4969
5011
  //#endregion
@@ -7021,6 +7063,7 @@ function secretsStore(options) {
7021
7063
  return `
7022
7064
  // Deployed stages keep their secrets in SSM, in the account each stage
7023
7065
  // deploys to: \`gkm secrets:set <KEY> '…' --stage <stage>\` writes there.
7066
+ // Past 8 KB a stage needs { provider: 'secrets-manager', region } instead.
7024
7067
  store: { provider: 'ssm', region: '${options.region}' },`;
7025
7068
  }
7026
7069
  /**
@@ -10116,8 +10159,8 @@ ${dbPasswordEntries.map(([key, value]) => `${key}=${value}`).join("\n")}
10116
10159
  //#region src/secrets/index.ts
10117
10160
  const logger$2 = console;
10118
10161
  /**
10119
- * The store the stage named on the command line keeps its secrets in — SSM in
10120
- * its account, for a deployed stage kept there. Outside any workspace nothing
10162
+ * The store the stage named on the command line keeps its secrets in — SSM or
10163
+ * Secrets Manager in its account, for a deployed stage kept there. Outside any workspace nothing
10121
10164
  * names a store, so it is the file.
10122
10165
  */
10123
10166
  async function storeFor(stage) {
@@ -10353,7 +10396,7 @@ const logger$1 = console;
10353
10396
  *
10354
10397
  * Orchestrates:
10355
10398
  * 1. Load workspace config
10356
- * 2. Resolve secrets (local → SSM → generate fresh)
10399
+ * 2. Resolve secrets (local → the stage's store → generate fresh)
10357
10400
  * 3. Write docker/.env from secrets
10358
10401
  * 4. Start Docker services
10359
10402
  */
@@ -10521,7 +10564,7 @@ function reconcileSecrets(secrets, workspace, containers = []) {
10521
10564
  /**
10522
10565
  * Build a fresh StageSecrets object for a workspace: service credentials,
10523
10566
  * connection URLs, and custom secrets. Pure — does not write to disk or touch
10524
- * SSM. Service passwords are freshly randomized, so the result must be the same
10567
+ * any store. Service passwords are freshly randomized, so the result must be the same
10525
10568
  * one used to start the matching Docker containers.
10526
10569
  * @internal Exported for reuse by `gkm test` auto-setup.
10527
10570
  */
@@ -10754,7 +10797,7 @@ function testDatabases(reconciled) {
10754
10797
  * starts without the reference data the app needs.
10755
10798
  */
10756
10799
  async function migrateTestStage(workspace, env) {
10757
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs"));
10800
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs"));
10758
10801
  const { discover } = await Promise.resolve().then(() => require("./discover-D1It5r_h.cjs")).then((n) => n.discover_exports);
10759
10802
  const sources = {};
10760
10803
  const manifest = await discover({
@@ -11187,7 +11230,7 @@ program.command("migrate").description("Apply each database construct's migratio
11187
11230
  try {
11188
11231
  const globalOptions = program.opts();
11189
11232
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11190
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs"));
11233
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs"));
11191
11234
  await migrateCommand({
11192
11235
  ...options,
11193
11236
  ...construct ? { construct } : {}
@@ -11201,7 +11244,7 @@ program.command("seed").description("Migrate, then run each database construct's
11201
11244
  try {
11202
11245
  const globalOptions = program.opts();
11203
11246
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11204
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs"));
11247
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs"));
11205
11248
  await seedCommand({
11206
11249
  ...options,
11207
11250
  ...construct ? { construct } : {}
@@ -11215,7 +11258,7 @@ program.command("migration").description("Write a construct's next migration: an
11215
11258
  try {
11216
11259
  const globalOptions = program.opts();
11217
11260
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11218
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-B0FCZNkp.cjs"));
11261
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-D5_-ylI1.cjs"));
11219
11262
  await migrationCommand({
11220
11263
  construct,
11221
11264
  ...name ? { name } : {}
@@ -11260,7 +11303,7 @@ program.command("docker").description("Generate Docker deployment files").option
11260
11303
  process.exit(1);
11261
11304
  }
11262
11305
  });
11263
- program.command("compose").description("Run the workspace's APIs and sites for a stage as one Docker Compose stack behind Caddy").requiredOption("--stage <stage>", "Stage to run — always named, so a stack is never a deployed stage by accident").option("--tag <tag>", "Run the images CI pushed at this tag (sites: <tag>-<stage>); nothing is built").option("--build", "Build images from this checkout, tagged with the commit").option("--pull", "Pull images (at --tag, or latest) rather than build them").option("--dry-run", "Write the files and print the plan; start nothing").option("--down", "Stop the stage's stack (its volumes are kept)").option("--allow-dev-services <list>", "Deployed stage: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade").action(async (options) => {
11306
+ program.command("compose").description("Run the workspace's APIs and sites for a stage as one Docker Compose stack behind Caddy").requiredOption("--stage <stage>", "Stage to run — always named, so a stack is never a deployed stage by accident").option("--tag <tag>", "Run the images CI pushed at this tag (sites: <tag>-<stage>); nothing is built").option("--build", "Build images from this checkout, tagged with the commit").option("--pull", "Pull images (at --tag, or latest) rather than build them").option("--push", "With --build: push every image to deploy.registry and start nothing (for CI)").option("--digests-file <path>", "With --push: write each image as <ref>@sha256:… (JSON). With --tag: run the images at those digests").option("--dry-run", "Write the files and print the plan; start nothing").option("--down", "Stop the stage's stack (its volumes are kept)").option("--allow-dev-services <list>", "Deployed stage: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade").action(async (options) => {
11264
11307
  try {
11265
11308
  const globalOptions = program.opts();
11266
11309
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
@@ -11309,7 +11352,7 @@ program.command("secrets:add").description("Build the keys a stage must be given
11309
11352
  try {
11310
11353
  const globalOptions = program.opts();
11311
11354
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11312
- const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-Djrr12Xc.cjs"));
11355
+ const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-j2yI3cbS.cjs"));
11313
11356
  await secretsAddCommand(options);
11314
11357
  } catch (error) {
11315
11358
  console.error(formatError(error));
@@ -11320,7 +11363,7 @@ program.command("encryption:rotate").description("Add a new current key to an En
11320
11363
  try {
11321
11364
  const globalOptions = program.opts();
11322
11365
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11323
- const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-DSkJdoyk.cjs"));
11366
+ const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-vS3Qzw73.cjs"));
11324
11367
  await encryptionRotateCommand(construct, options);
11325
11368
  } catch (error) {
11326
11369
  console.error(formatError(error));
@@ -11331,7 +11374,7 @@ program.command("encryption:retire").description("Remove an old key from an Encr
11331
11374
  try {
11332
11375
  const globalOptions = program.opts();
11333
11376
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11334
- const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-DSkJdoyk.cjs"));
11377
+ const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-vS3Qzw73.cjs"));
11335
11378
  await encryptionRetireCommand(construct, key, options);
11336
11379
  } catch (error) {
11337
11380
  console.error(formatError(error));
@@ -11374,7 +11417,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
11374
11417
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11375
11418
  const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
11376
11419
  const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-CuCQBa5-.cjs"));
11377
- const { secretsStoreFor } = await Promise.resolve().then(() => require("./state-DCwRWyh-.cjs")).then((n) => n.store_exports);
11420
+ const { secretsStoreFor } = await Promise.resolve().then(() => require("./state-C2qi0iQw.cjs")).then((n) => n.store_exports);
11378
11421
  const { workspace } = await loadWorkspaceConfig();
11379
11422
  const stage = options.stage ?? workspace.stages.local;
11380
11423
  const store = await secretsStoreFor(workspace, stage);
@@ -11383,7 +11426,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
11383
11426
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
11384
11427
  process.exit(1);
11385
11428
  }
11386
- const { derivedContainers } = await Promise.resolve().then(() => require("./state-DCwRWyh-.cjs")).then((n) => n.workspace_exports);
11429
+ const { derivedContainers } = await Promise.resolve().then(() => require("./state-C2qi0iQw.cjs")).then((n) => n.workspace_exports);
11387
11430
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
11388
11431
  if (!result) {
11389
11432
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -11397,8 +11440,19 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
11397
11440
  process.exit(1);
11398
11441
  }
11399
11442
  });
11443
+ program.command("secrets:migrate").description("Copy a deployed stage's secrets from the configured store to another (file, ssm, secrets-manager)").requiredOption("--stage <stage>", "A deployed stage").requiredOption("--to <provider>", "file, ssm or secrets-manager").option("--region <region>", "The target's AWS region (default: the configured store's)").option("--profile <profile>", "AWS profile for the stage's account").option("--force", "Replace a stage the target already holds").action(async (options) => {
11444
+ try {
11445
+ const globalOptions = program.opts();
11446
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11447
+ const { secretsMigrateCommand } = await Promise.resolve().then(() => require("./migrate-BRbYtFXG.cjs"));
11448
+ await secretsMigrateCommand(options);
11449
+ } catch (error) {
11450
+ console.error(formatError(error));
11451
+ process.exit(1);
11452
+ }
11453
+ });
11400
11454
  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) => {
11401
- const { deployCli } = await Promise.resolve().then(() => require("./cli-Bx0sUzxH.cjs"));
11455
+ const { deployCli } = await Promise.resolve().then(() => require("./cli-CNanUB7a.cjs"));
11402
11456
  const globalOptions = program.opts();
11403
11457
  const code = await deployCli({
11404
11458
  cwd: (0, node_path.resolve)(globalOptions.cwd ?? process.cwd()),
@@ -11415,7 +11469,7 @@ program.command("deploy").description("Deploy a stage through its target").optio
11415
11469
  });
11416
11470
  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) => {
11417
11471
  try {
11418
- const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-DJy3t696.cjs")).then((n) => n.rollback_exports);
11472
+ const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-C9N5lKVf.cjs")).then((n) => n.rollback_exports);
11419
11473
  const { terminalCredentials } = await Promise.resolve().then(() => require("./terminal-BL5E0xbR.cjs"));
11420
11474
  const globalOptions = program.opts();
11421
11475
  await rollbackStage({
@@ -11451,7 +11505,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
11451
11505
  try {
11452
11506
  const globalOptions = program.opts();
11453
11507
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11454
- const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BvN3CfxM.cjs"));
11508
+ const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-ClkdCOL9.cjs"));
11455
11509
  await deployGithubCommand(options);
11456
11510
  } catch (error) {
11457
11511
  console.error(formatError(error));