@geekmidas/cli 9.0.2 → 10.0.0-alpha.0
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 +71 -120
- package/dist/{CachedStateProvider-BdX7klRc.cjs → CachedStateProvider-BLo7zv7S.cjs} +1 -1
- package/dist/CachedStateProvider-BxoAm-B2.mjs +3 -0
- package/dist/{CachedStateProvider-klLWZXWF.cjs → CachedStateProvider-CqPdW7CB.cjs} +1 -1
- package/dist/{CachedStateProvider-klLWZXWF.cjs.map → CachedStateProvider-CqPdW7CB.cjs.map} +1 -1
- package/dist/{CachedStateProvider-CzyFct42.mjs → CachedStateProvider-DTniehMP.mjs} +1 -1
- package/dist/{CachedStateProvider-CzyFct42.mjs.map → CachedStateProvider-DTniehMP.mjs.map} +1 -1
- package/dist/{HostingerProvider-B2ZYz7Yc.mjs → HostingerProvider-Cft7lEYr.mjs} +4 -3
- package/dist/HostingerProvider-Cft7lEYr.mjs.map +1 -0
- package/dist/{HostingerProvider-CrHfsgz9.cjs → HostingerProvider-h3EbEp-Z.cjs} +4 -3
- package/dist/HostingerProvider-h3EbEp-Z.cjs.map +1 -0
- package/dist/{LocalStateProvider-CP49rjzt.mjs → LocalStateProvider-Bn6tS-oL.mjs} +1 -1
- package/dist/{LocalStateProvider-CP49rjzt.mjs.map → LocalStateProvider-Bn6tS-oL.mjs.map} +1 -1
- package/dist/{LocalStateProvider-CalzNfNA.cjs → LocalStateProvider-Db9SEjyH.cjs} +1 -1
- package/dist/{LocalStateProvider-CalzNfNA.cjs.map → LocalStateProvider-Db9SEjyH.cjs.map} +1 -1
- package/dist/{Route53Provider-tlgBzrRQ.mjs → Route53Provider-RdpUDJQk.mjs} +1 -1
- package/dist/{Route53Provider-tlgBzrRQ.mjs.map → Route53Provider-RdpUDJQk.mjs.map} +1 -1
- package/dist/{Route53Provider-DwgXiLxt.cjs → Route53Provider-di2fMM5N.cjs} +1 -1
- package/dist/{Route53Provider-DwgXiLxt.cjs.map → Route53Provider-di2fMM5N.cjs.map} +1 -1
- package/dist/{SSMStateProvider-BlrTiV5m.mjs → SSMStateProvider-BRt2py-A.mjs} +1 -1
- package/dist/{SSMStateProvider-BlrTiV5m.mjs.map → SSMStateProvider-BRt2py-A.mjs.map} +1 -1
- package/dist/{SSMStateProvider-Bt6r8CTL.cjs → SSMStateProvider-DyX8s9HI.cjs} +1 -1
- package/dist/{SSMStateProvider-Bt6r8CTL.cjs.map → SSMStateProvider-DyX8s9HI.cjs.map} +1 -1
- package/dist/{backup-provisioner-Xunq-p_8.mjs → backup-provisioner-Bgj5Vi_L.mjs} +2 -2
- package/dist/{backup-provisioner-Xunq-p_8.mjs.map → backup-provisioner-Bgj5Vi_L.mjs.map} +1 -1
- package/dist/{backup-provisioner-B3HBN-2k.cjs → backup-provisioner-BrsHwYG0.cjs} +2 -2
- package/dist/{backup-provisioner-B3HBN-2k.cjs.map → backup-provisioner-BrsHwYG0.cjs.map} +1 -1
- package/dist/{bundler-Dufq3uvI.cjs → bundler-BY1OmV1e.cjs} +44 -14
- package/dist/bundler-BY1OmV1e.cjs.map +1 -0
- package/dist/{bundler-DkA4qzUD.mjs → bundler-Be8Zg4Wd.mjs} +45 -15
- package/dist/bundler-Be8Zg4Wd.mjs.map +1 -0
- package/dist/config-D8o6I_7Z.mjs +469 -0
- package/dist/config-D8o6I_7Z.mjs.map +1 -0
- package/dist/config-DbPE1KXF.cjs +535 -0
- package/dist/config-DbPE1KXF.cjs.map +1 -0
- package/dist/config.cjs +3 -2
- package/dist/config.d.cts +2 -2
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +2 -2
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +3 -2
- package/dist/{credentials-s1kLcIzK.mjs → credentials-B5zRHdAl.mjs} +21 -6
- package/dist/credentials-B5zRHdAl.mjs.map +1 -0
- package/dist/{credentials-C8DWtnMY.cjs → credentials-BapzjyV5.cjs} +26 -5
- package/dist/credentials-BapzjyV5.cjs.map +1 -0
- package/dist/credentials-Dh0Q6HzY.mjs +2548 -0
- package/dist/credentials-Dh0Q6HzY.mjs.map +1 -0
- package/dist/credentials-K961ThG3.cjs +2680 -0
- package/dist/credentials-K961ThG3.cjs.map +1 -0
- package/dist/deploy/sniffer-routes-worker.cjs +6 -2
- package/dist/deploy/sniffer-routes-worker.cjs.map +1 -1
- package/dist/deploy/sniffer-routes-worker.mjs +6 -2
- package/dist/deploy/sniffer-routes-worker.mjs.map +1 -1
- package/dist/discover-CAlFgYec.mjs +229 -0
- package/dist/discover-CAlFgYec.mjs.map +1 -0
- package/dist/discover-DTmFeloL.cjs +271 -0
- package/dist/discover-DTmFeloL.cjs.map +1 -0
- package/dist/dokploy-api-BS2xnJLZ.mjs +3 -0
- package/dist/{dokploy-api-CqOIKHme.cjs → dokploy-api-BsVH0y_s.cjs} +141 -32
- package/dist/dokploy-api-BsVH0y_s.cjs.map +1 -0
- package/dist/dokploy-api-BuxDRo3l.cjs +3 -0
- package/dist/{dokploy-api-sfZFlWuE.mjs → dokploy-api-aTFPz7_4.mjs} +141 -32
- package/dist/dokploy-api-aTFPz7_4.mjs.map +1 -0
- package/dist/emit-CbcRolsa.cjs +236 -0
- package/dist/emit-CbcRolsa.cjs.map +1 -0
- package/dist/emit-CiZS_5Ub.mjs +206 -0
- package/dist/emit-CiZS_5Ub.mjs.map +1 -0
- package/dist/{encryption-MfXAiFTm.cjs → encryption-C6jaU0hE.cjs} +1 -1
- package/dist/{encryption-MfXAiFTm.cjs.map → encryption-C6jaU0hE.cjs.map} +1 -1
- package/dist/{encryption-BVS7Vmzs.cjs → encryption-CHzzeR8a.cjs} +1 -1
- package/dist/encryption-CQUncu7v.mjs +3 -0
- package/dist/{encryption-CO5Q4Bhf.mjs → encryption-D-abyhZx.mjs} +1 -1
- package/dist/{encryption-CO5Q4Bhf.mjs.map → encryption-D-abyhZx.mjs.map} +1 -1
- package/dist/fullstack-secrets-C-GGohke.cjs +111 -0
- package/dist/fullstack-secrets-C-GGohke.cjs.map +1 -0
- package/dist/fullstack-secrets-D1o9-G5l.mjs +87 -0
- package/dist/fullstack-secrets-D1o9-G5l.mjs.map +1 -0
- package/dist/{fullstack-secrets-BYzi6Hwl.cjs → generator-CNzBw7g5.cjs} +1 -114
- package/dist/generator-CNzBw7g5.cjs.map +1 -0
- package/dist/{fullstack-secrets-l8s3II_H.mjs → generator-VE2JrFlY.mjs} +2 -85
- package/dist/generator-VE2JrFlY.mjs.map +1 -0
- package/dist/index-BThUzEIp.d.mts +175 -0
- package/dist/index-BThUzEIp.d.mts.map +1 -0
- package/dist/index-CHB4tSzX.d.cts +175 -0
- package/dist/index-CHB4tSzX.d.cts.map +1 -0
- package/dist/index.cjs +2329 -1584
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2306 -1561
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-Cfwi0fqF.mjs → openapi-CgpMWMmM.mjs} +174 -95
- package/dist/openapi-CgpMWMmM.mjs.map +1 -0
- package/dist/{openapi-BzNOC7_i.cjs → openapi-CljONd_M.cjs} +175 -108
- package/dist/openapi-CljONd_M.cjs.map +1 -0
- package/dist/{openapi-react-query-C4iIvpPf.mjs → openapi-react-query-Byltvm_7.mjs} +2 -2
- package/dist/openapi-react-query-Byltvm_7.mjs.map +1 -0
- package/dist/{openapi-react-query-CYWik72n.cjs → openapi-react-query-CmJ1xDbn.cjs} +2 -2
- package/dist/openapi-react-query-CmJ1xDbn.cjs.map +1 -0
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +4 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +4 -3
- package/dist/reconcile/public.cjs +9 -0
- package/dist/reconcile/public.d.cts +125 -0
- package/dist/reconcile/public.d.cts.map +1 -0
- package/dist/reconcile/public.d.mts +125 -0
- package/dist/reconcile/public.d.mts.map +1 -0
- package/dist/reconcile/public.mjs +4 -0
- package/dist/{reconcile-B2FoJE0a.mjs → reconcile-CFs8C_1a.mjs} +5 -4
- package/dist/reconcile-CFs8C_1a.mjs.map +1 -0
- package/dist/{reconcile-BzqKJ2Rt.cjs → reconcile-D0pimNiy.cjs} +5 -4
- package/dist/reconcile-D0pimNiy.cjs.map +1 -0
- package/dist/setup-CJiQM2pX.cjs +473 -0
- package/dist/setup-CJiQM2pX.cjs.map +1 -0
- package/dist/setup-DMtU3p41.cjs +11 -0
- package/dist/setup-DOsYueeQ.mjs +443 -0
- package/dist/setup-DOsYueeQ.mjs.map +1 -0
- package/dist/setup-DSutDAlt.mjs +11 -0
- package/dist/{storage-B1wvztiJ.cjs → storage-BJmzYxt8.cjs} +1 -1
- package/dist/{storage-B1wvztiJ.cjs.map → storage-BJmzYxt8.cjs.map} +1 -1
- package/dist/{storage-DOEtT2Hr.cjs → storage-BM9hGpgv.cjs} +1 -1
- package/dist/{storage-dbb9RyBl.mjs → storage-Bi24WfoW.mjs} +1 -1
- package/dist/{storage-dbb9RyBl.mjs.map → storage-Bi24WfoW.mjs.map} +1 -1
- package/dist/{storage-Cs4WBsc4.mjs → storage-CYlGwWTj.mjs} +1 -1
- package/dist/{sync-CSooqRQ8.mjs → sync-CmEuNZsB.mjs} +2 -2
- package/dist/{sync-CSooqRQ8.mjs.map → sync-CmEuNZsB.mjs.map} +1 -1
- package/dist/sync-D306yOWu.cjs +4 -0
- package/dist/{sync-o_CtEbvR.cjs → sync-SizaChmC.cjs} +2 -2
- package/dist/{sync-o_CtEbvR.cjs.map → sync-SizaChmC.cjs.map} +1 -1
- package/dist/{sync-B5UHXwRM.mjs → sync-hOqAWHR6.mjs} +1 -1
- package/dist/{index-Bw548Bta.d.mts → types-C-arnQ1r.d.mts} +590 -143
- package/dist/types-C-arnQ1r.d.mts.map +1 -0
- package/dist/{index-DTpkeFb8.d.cts → types-abJQuk7m.d.cts} +590 -143
- package/dist/types-abJQuk7m.d.cts.map +1 -0
- package/dist/workspace/index.cjs +5 -1
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +2 -2
- package/dist/{workspace-D-37Ylqo.mjs → workspace-7FqprxuJ.mjs} +117 -30
- package/dist/workspace-7FqprxuJ.mjs.map +1 -0
- package/dist/workspace-8acupeaI.cjs +9 -0
- package/dist/{workspace-CQTT7HJQ.cjs → workspace-XvqO9jIv.cjs} +139 -28
- package/dist/workspace-XvqO9jIv.cjs.map +1 -0
- package/dist/workspace-yP5AHnrn.mjs +8 -0
- package/package.json +26 -9
- package/CHANGELOG.md +0 -650
- package/FUNCTION_CRON_SUPPORT.md +0 -266
- package/dist/CachedStateProvider-GcGziXh1.mjs +0 -3
- package/dist/HostingerProvider-B2ZYz7Yc.mjs.map +0 -1
- package/dist/HostingerProvider-CrHfsgz9.cjs.map +0 -1
- package/dist/bundler-DkA4qzUD.mjs.map +0 -1
- package/dist/bundler-Dufq3uvI.cjs.map +0 -1
- package/dist/config-Bbu1JKvf.mjs +0 -211
- package/dist/config-Bbu1JKvf.mjs.map +0 -1
- package/dist/config-DujV8DbR.cjs +0 -253
- package/dist/config-DujV8DbR.cjs.map +0 -1
- package/dist/credentials-C8DWtnMY.cjs.map +0 -1
- package/dist/credentials-s1kLcIzK.mjs.map +0 -1
- package/dist/dokploy-api-BPYkG-ZZ.cjs +0 -3
- package/dist/dokploy-api-BiSzWM4v.mjs +0 -3
- package/dist/dokploy-api-CqOIKHme.cjs.map +0 -1
- package/dist/dokploy-api-sfZFlWuE.mjs.map +0 -1
- package/dist/encryption-Bd_m4q3g.mjs +0 -3
- package/dist/fullstack-secrets-BYzi6Hwl.cjs.map +0 -1
- package/dist/fullstack-secrets-l8s3II_H.mjs.map +0 -1
- package/dist/index-Bw548Bta.d.mts.map +0 -1
- package/dist/index-DTpkeFb8.d.cts.map +0 -1
- package/dist/openapi-BzNOC7_i.cjs.map +0 -1
- package/dist/openapi-Cfwi0fqF.mjs.map +0 -1
- package/dist/openapi-react-query-C4iIvpPf.mjs.map +0 -1
- package/dist/openapi-react-query-CYWik72n.cjs.map +0 -1
- package/dist/reconcile-B2FoJE0a.mjs.map +0 -1
- package/dist/reconcile-BzqKJ2Rt.cjs.map +0 -1
- package/dist/setup-DDXUXzzl.mjs +0 -765
- package/dist/setup-DDXUXzzl.mjs.map +0 -1
- package/dist/setup-DLwhfyt-.cjs +0 -8
- package/dist/setup-Dh-B7YTX.mjs +0 -8
- package/dist/setup-WZ-xqAQO.cjs +0 -849
- package/dist/setup-WZ-xqAQO.cjs.map +0 -1
- package/dist/sync-BLA94rgC.cjs +0 -4
- package/dist/types-B3GQUg3k.d.mts +0 -280
- package/dist/types-B3GQUg3k.d.mts.map +0 -1
- package/dist/types-BWQDiooe.d.cts +0 -280
- package/dist/types-BWQDiooe.d.cts.map +0 -1
- package/dist/workspace-CQTT7HJQ.cjs.map +0 -1
- package/dist/workspace-D-37Ylqo.mjs.map +0 -1
- package/docs/OPENAPI_TYPESCRIPT_DESIGN.md +0 -408
- package/docs/dev-server-resilience-design.md +0 -189
- package/docs/manifest-refactor-design.md +0 -287
- package/examples/cron-example.ts +0 -45
- package/examples/env.ts +0 -33
- package/examples/function-example.ts +0 -40
- package/examples/gkm.config.json +0 -22
- package/examples/gkm.config.ts +0 -14
- package/examples/gkm.minimal.config.json +0 -7
- package/examples/gkm.production.config.json +0 -27
- package/examples/logger.ts +0 -10
- package/scripts/sync-versions.ts +0 -108
- package/src/__tests__/EndpointGenerator.hooks.spec.ts +0 -204
- package/src/__tests__/config.spec.ts +0 -422
- package/src/__tests__/loadEnvFiles.spec.ts +0 -131
- package/src/__tests__/normalizeHooksConfig.spec.ts +0 -63
- package/src/__tests__/openapi-react-query.spec.ts +0 -506
- package/src/__tests__/openapi.spec.ts +0 -625
- package/src/__tests__/test-helpers.ts +0 -181
- package/src/auth/__tests__/credentials.spec.ts +0 -331
- package/src/auth/__tests__/index.spec.ts +0 -237
- package/src/auth/credentials.ts +0 -286
- package/src/auth/index.ts +0 -233
- package/src/build/__tests__/bundler.spec.ts +0 -446
- package/src/build/__tests__/endpoint-analyzer.spec.ts +0 -623
- package/src/build/__tests__/handler-templates.spec.ts +0 -1287
- package/src/build/__tests__/index-new.spec.ts +0 -550
- package/src/build/__tests__/manifests.spec.ts +0 -583
- package/src/build/__tests__/partitions.spec.ts +0 -110
- package/src/build/__tests__/workspace-build.spec.ts +0 -215
- package/src/build/bundler.ts +0 -256
- package/src/build/endpoint-analyzer.ts +0 -236
- package/src/build/handler-templates.ts +0 -1253
- package/src/build/index.ts +0 -616
- package/src/build/manifests.ts +0 -285
- package/src/build/partitions.ts +0 -58
- package/src/build/providerResolver.ts +0 -184
- package/src/build/types.ts +0 -104
- package/src/config.ts +0 -330
- package/src/credentials/__tests__/fullDockerPorts.spec.ts +0 -144
- package/src/credentials/__tests__/helpers.ts +0 -112
- package/src/credentials/__tests__/prepareEntryCredentials.spec.ts +0 -125
- package/src/credentials/__tests__/readonlyDockerPorts.spec.ts +0 -190
- package/src/credentials/__tests__/workspaceCredentials.spec.ts +0 -209
- package/src/credentials/index.ts +0 -843
- package/src/debug.ts +0 -68
- package/src/deploy/CachedStateProvider.ts +0 -86
- package/src/deploy/LocalStateProvider.ts +0 -57
- package/src/deploy/SSMStateProvider.ts +0 -117
- package/src/deploy/StateProvider.ts +0 -175
- package/src/deploy/__tests__/CachedStateProvider.spec.ts +0 -235
- package/src/deploy/__tests__/HostingerProvider.spec.ts +0 -347
- package/src/deploy/__tests__/LocalStateProvider.spec.ts +0 -130
- package/src/deploy/__tests__/Route53Provider.spec.ts +0 -425
- package/src/deploy/__tests__/SSMStateProvider.spec.ts +0 -201
- package/src/deploy/__tests__/__fixtures__/entry-apps/async-entry.ts +0 -24
- package/src/deploy/__tests__/__fixtures__/entry-apps/nested-config-entry.ts +0 -24
- package/src/deploy/__tests__/__fixtures__/entry-apps/no-env-entry.ts +0 -12
- package/src/deploy/__tests__/__fixtures__/entry-apps/simple-entry.ts +0 -14
- package/src/deploy/__tests__/__fixtures__/entry-apps/throwing-entry.ts +0 -16
- package/src/deploy/__tests__/__fixtures__/env-parsers/non-function-export.ts +0 -10
- package/src/deploy/__tests__/__fixtures__/env-parsers/optional-env-parser.ts +0 -21
- package/src/deploy/__tests__/__fixtures__/env-parsers/parseable-env-parser.ts +0 -18
- package/src/deploy/__tests__/__fixtures__/env-parsers/throwing-env-parser.ts +0 -16
- package/src/deploy/__tests__/__fixtures__/env-parsers/valid-env-parser.ts +0 -16
- package/src/deploy/__tests__/__fixtures__/route-apps/endpoints/auth.ts +0 -16
- package/src/deploy/__tests__/__fixtures__/route-apps/endpoints/health.ts +0 -13
- package/src/deploy/__tests__/__fixtures__/route-apps/endpoints/users.ts +0 -15
- package/src/deploy/__tests__/__fixtures__/route-apps/services.ts +0 -55
- package/src/deploy/__tests__/backup-provisioner.spec.ts +0 -428
- package/src/deploy/__tests__/createDnsProvider.spec.ts +0 -195
- package/src/deploy/__tests__/createStateProvider.spec.ts +0 -126
- package/src/deploy/__tests__/dns-orchestration.spec.ts +0 -192
- package/src/deploy/__tests__/dns-verification.spec.ts +0 -229
- package/src/deploy/__tests__/docker.spec.ts +0 -149
- package/src/deploy/__tests__/dokploy-api.spec.ts +0 -697
- package/src/deploy/__tests__/dokploy.spec.ts +0 -435
- package/src/deploy/__tests__/domain.spec.ts +0 -235
- package/src/deploy/__tests__/env-resolver.spec.ts +0 -903
- package/src/deploy/__tests__/index.spec.ts +0 -1091
- package/src/deploy/__tests__/init.spec.ts +0 -793
- package/src/deploy/__tests__/secrets.spec.ts +0 -303
- package/src/deploy/__tests__/sniffer.spec.ts +0 -838
- package/src/deploy/__tests__/state-e2e.spec.ts +0 -387
- package/src/deploy/__tests__/state.spec.ts +0 -876
- package/src/deploy/__tests__/undeploy.spec.ts +0 -758
- package/src/deploy/backup-provisioner.ts +0 -316
- package/src/deploy/dns/DnsProvider.ts +0 -201
- package/src/deploy/dns/HostingerProvider.ts +0 -174
- package/src/deploy/dns/Route53Provider.ts +0 -340
- package/src/deploy/dns/hostinger-api.ts +0 -261
- package/src/deploy/dns/index.ts +0 -627
- package/src/deploy/docker.ts +0 -260
- package/src/deploy/dokploy-api.ts +0 -1101
- package/src/deploy/dokploy.ts +0 -177
- package/src/deploy/domain.ts +0 -134
- package/src/deploy/env-resolver.ts +0 -305
- package/src/deploy/index.ts +0 -2094
- package/src/deploy/init.ts +0 -427
- package/src/deploy/secrets.ts +0 -187
- package/src/deploy/sniffer-envkit-patch.ts +0 -61
- package/src/deploy/sniffer-hooks.ts +0 -57
- package/src/deploy/sniffer-loader.ts +0 -28
- package/src/deploy/sniffer-routes-worker.ts +0 -104
- package/src/deploy/sniffer-worker.ts +0 -75
- package/src/deploy/sniffer.ts +0 -578
- package/src/deploy/state-commands.ts +0 -274
- package/src/deploy/state.ts +0 -482
- package/src/deploy/types.ts +0 -102
- package/src/deploy/undeploy.ts +0 -407
- package/src/dev/__tests__/entry-integration.spec.ts +0 -347
- package/src/dev/__tests__/entry.spec.ts +0 -144
- package/src/dev/__tests__/index.spec.ts +0 -2084
- package/src/dev/index.ts +0 -1649
- package/src/docker/__tests__/compose.spec.ts +0 -1142
- package/src/docker/__tests__/templates.spec.ts +0 -694
- package/src/docker/compose.ts +0 -808
- package/src/docker/index.ts +0 -523
- package/src/docker/templates.ts +0 -1067
- package/src/exec/index.ts +0 -118
- package/src/generators/CronGenerator.ts +0 -105
- package/src/generators/EndpointGenerator.ts +0 -954
- package/src/generators/FunctionGenerator.ts +0 -117
- package/src/generators/Generator.ts +0 -147
- package/src/generators/OpenApiTsGenerator.ts +0 -821
- package/src/generators/QueueGenerator.ts +0 -245
- package/src/generators/SubscriberGenerator.ts +0 -282
- package/src/generators/TopicGenerator.ts +0 -45
- package/src/generators/__tests__/CronGenerator.spec.ts +0 -445
- package/src/generators/__tests__/EndpointGenerator.spec.ts +0 -544
- package/src/generators/__tests__/FunctionGenerator.spec.ts +0 -256
- package/src/generators/__tests__/Generator.bustCache.spec.ts +0 -72
- package/src/generators/__tests__/OpenApiTsGenerator.registry.spec.ts +0 -98
- package/src/generators/__tests__/OpenApiTsGenerator.responseType.spec.ts +0 -56
- package/src/generators/__tests__/QueueGenerator.spec.ts +0 -141
- package/src/generators/__tests__/SubscriberGenerator.spec.ts +0 -410
- package/src/generators/index.ts +0 -11
- package/src/index.ts +0 -972
- package/src/init/__tests__/generators.spec.ts +0 -1070
- package/src/init/__tests__/init.spec.ts +0 -577
- package/src/init/__tests__/utils.spec.ts +0 -104
- package/src/init/generators/auth.ts +0 -225
- package/src/init/generators/config.ts +0 -316
- package/src/init/generators/docker.ts +0 -388
- package/src/init/generators/env.ts +0 -62
- package/src/init/generators/index.ts +0 -6
- package/src/init/generators/mobile-expo.ts +0 -576
- package/src/init/generators/models.ts +0 -153
- package/src/init/generators/monorepo.ts +0 -475
- package/src/init/generators/package.ts +0 -95
- package/src/init/generators/source.ts +0 -15
- package/src/init/generators/test.ts +0 -178
- package/src/init/generators/ui.ts +0 -1473
- package/src/init/generators/web-tanstack.ts +0 -348
- package/src/init/generators/web.ts +0 -363
- package/src/init/index.ts +0 -542
- package/src/init/templates/api.ts +0 -404
- package/src/init/templates/index.ts +0 -342
- package/src/init/templates/minimal.ts +0 -207
- package/src/init/templates/serverless.ts +0 -148
- package/src/init/templates/worker.ts +0 -216
- package/src/init/utils.ts +0 -197
- package/src/init/versions.ts +0 -52
- package/src/openapi-react-query.ts +0 -288
- package/src/openapi.ts +0 -259
- package/src/secrets/__tests__/encryption.spec.ts +0 -226
- package/src/secrets/__tests__/generator.spec.ts +0 -575
- package/src/secrets/__tests__/index.spec.ts +0 -91
- package/src/secrets/__tests__/reconcile.spec.ts +0 -123
- package/src/secrets/__tests__/storage.spec.ts +0 -645
- package/src/secrets/encryption.ts +0 -91
- package/src/secrets/generator.ts +0 -329
- package/src/secrets/index.ts +0 -417
- package/src/secrets/keystore.ts +0 -144
- package/src/secrets/reconcile.ts +0 -53
- package/src/secrets/storage.ts +0 -337
- package/src/secrets/sync.ts +0 -136
- package/src/secrets/types.ts +0 -70
- package/src/setup/__tests__/auto-setup.spec.ts +0 -147
- package/src/setup/__tests__/reconcile-secrets.spec.ts +0 -439
- package/src/setup/fullstack-secrets.ts +0 -140
- package/src/setup/index.ts +0 -411
- package/src/test/__tests__/__fixtures__/workspace.ts +0 -104
- package/src/test/__tests__/api.spec.ts +0 -199
- package/src/test/__tests__/auth.spec.ts +0 -162
- package/src/test/__tests__/index.spec.ts +0 -502
- package/src/test/__tests__/web.spec.ts +0 -210
- package/src/test/index.ts +0 -198
- package/src/types.ts +0 -363
- package/src/upgrade/__tests__/index.spec.ts +0 -354
- package/src/upgrade/index.ts +0 -253
- package/src/workspace/__tests__/client-generator.spec.ts +0 -326
- package/src/workspace/__tests__/index.spec.ts +0 -766
- package/src/workspace/__tests__/publicEnv.spec.ts +0 -64
- package/src/workspace/__tests__/schema.spec.ts +0 -737
- package/src/workspace/__tests__/type-inference.spec.ts +0 -251
- package/src/workspace/client-generator.ts +0 -109
- package/src/workspace/index.ts +0 -433
- package/src/workspace/publicEnv.ts +0 -57
- package/src/workspace/schema.ts +0 -861
- package/src/workspace/types.ts +0 -943
- package/tsconfig.json +0 -9
- package/tsdown.config.ts +0 -22
package/src/secrets/storage.ts
DELETED
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { basename, join } from 'node:path';
|
|
5
|
-
import { getOrCreateKey, readKey } from './keystore';
|
|
6
|
-
import type { EmbeddableSecrets, StageSecrets } from './types';
|
|
7
|
-
|
|
8
|
-
/** Default secrets directory relative to project root */
|
|
9
|
-
const SECRETS_DIR = '.gkm/secrets';
|
|
10
|
-
|
|
11
|
-
/** AES-256-GCM configuration */
|
|
12
|
-
const ALGORITHM = 'aes-256-gcm';
|
|
13
|
-
const IV_LENGTH = 12; // 96 bits for GCM
|
|
14
|
-
const AUTH_TAG_LENGTH = 16; // 128 bits
|
|
15
|
-
|
|
16
|
-
/** Encrypted secrets file structure */
|
|
17
|
-
interface EncryptedSecretsFile {
|
|
18
|
-
/** Version for future format changes */
|
|
19
|
-
version: 1;
|
|
20
|
-
/** Base64 encoded encrypted data (ciphertext + auth tag) */
|
|
21
|
-
encrypted: string;
|
|
22
|
-
/** Hex encoded IV */
|
|
23
|
-
iv: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get the secrets directory path.
|
|
28
|
-
*/
|
|
29
|
-
export function getSecretsDir(cwd = process.cwd()): string {
|
|
30
|
-
return join(cwd, SECRETS_DIR);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Get the secrets file path for a stage.
|
|
35
|
-
*/
|
|
36
|
-
export function getSecretsPath(stage: string, cwd = process.cwd()): string {
|
|
37
|
-
return join(getSecretsDir(cwd), `${stage}.json`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Check if secrets exist for a stage.
|
|
42
|
-
*/
|
|
43
|
-
export function secretsExist(stage: string, cwd = process.cwd()): boolean {
|
|
44
|
-
return existsSync(getSecretsPath(stage, cwd));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Initialize an empty StageSecrets object for a stage.
|
|
49
|
-
*/
|
|
50
|
-
export function initStageSecrets(stage: string): StageSecrets {
|
|
51
|
-
const now = new Date().toISOString();
|
|
52
|
-
return {
|
|
53
|
-
stage,
|
|
54
|
-
createdAt: now,
|
|
55
|
-
updatedAt: now,
|
|
56
|
-
services: {},
|
|
57
|
-
urls: {},
|
|
58
|
-
custom: {},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Encrypt secrets using a key.
|
|
64
|
-
*/
|
|
65
|
-
function encryptSecretsData(
|
|
66
|
-
secrets: StageSecrets,
|
|
67
|
-
keyHex: string,
|
|
68
|
-
): EncryptedSecretsFile {
|
|
69
|
-
const key = Buffer.from(keyHex, 'hex');
|
|
70
|
-
const iv = randomBytes(IV_LENGTH);
|
|
71
|
-
|
|
72
|
-
// Serialize secrets to JSON
|
|
73
|
-
const plaintext = JSON.stringify(secrets);
|
|
74
|
-
|
|
75
|
-
// Encrypt
|
|
76
|
-
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
77
|
-
const ciphertext = Buffer.concat([
|
|
78
|
-
cipher.update(plaintext, 'utf-8'),
|
|
79
|
-
cipher.final(),
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
// Get auth tag
|
|
83
|
-
const authTag = cipher.getAuthTag();
|
|
84
|
-
|
|
85
|
-
// Combine ciphertext + auth tag
|
|
86
|
-
const combined = Buffer.concat([ciphertext, authTag]);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
version: 1,
|
|
90
|
-
encrypted: combined.toString('base64'),
|
|
91
|
-
iv: iv.toString('hex'),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Decrypt secrets using a key.
|
|
97
|
-
*/
|
|
98
|
-
function decryptSecretsData(
|
|
99
|
-
data: EncryptedSecretsFile,
|
|
100
|
-
keyHex: string,
|
|
101
|
-
): StageSecrets {
|
|
102
|
-
const key = Buffer.from(keyHex, 'hex');
|
|
103
|
-
const ivBuffer = Buffer.from(data.iv, 'hex');
|
|
104
|
-
const combined = Buffer.from(data.encrypted, 'base64');
|
|
105
|
-
|
|
106
|
-
// Split ciphertext and auth tag
|
|
107
|
-
const ciphertext = combined.subarray(0, -AUTH_TAG_LENGTH);
|
|
108
|
-
const authTag = combined.subarray(-AUTH_TAG_LENGTH);
|
|
109
|
-
|
|
110
|
-
// Decrypt
|
|
111
|
-
const decipher = createDecipheriv(ALGORITHM, key, ivBuffer);
|
|
112
|
-
decipher.setAuthTag(authTag);
|
|
113
|
-
|
|
114
|
-
const plaintext = Buffer.concat([
|
|
115
|
-
decipher.update(ciphertext),
|
|
116
|
-
decipher.final(),
|
|
117
|
-
]);
|
|
118
|
-
|
|
119
|
-
return JSON.parse(plaintext.toString('utf-8')) as StageSecrets;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Read secrets for a stage (encrypted).
|
|
124
|
-
* Requires the decryption key to be present at ~/.gkm/{project}/{stage}.key
|
|
125
|
-
*
|
|
126
|
-
* @returns StageSecrets or null if not found
|
|
127
|
-
*/
|
|
128
|
-
export async function readStageSecrets(
|
|
129
|
-
stage: string,
|
|
130
|
-
cwd = process.cwd(),
|
|
131
|
-
): Promise<StageSecrets | null> {
|
|
132
|
-
const path = getSecretsPath(stage, cwd);
|
|
133
|
-
|
|
134
|
-
if (!existsSync(path)) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const content = await readFile(path, 'utf-8');
|
|
139
|
-
const data = JSON.parse(content);
|
|
140
|
-
|
|
141
|
-
// Check if this is an encrypted file (has version field)
|
|
142
|
-
if (data.version === 1 && data.encrypted && data.iv) {
|
|
143
|
-
const projectName = basename(cwd);
|
|
144
|
-
const key = await readKey(stage, projectName);
|
|
145
|
-
|
|
146
|
-
if (!key) {
|
|
147
|
-
throw new Error(
|
|
148
|
-
`Decryption key not found for stage "${stage}". ` +
|
|
149
|
-
`Expected key at: ~/.gkm/${projectName}/${stage}.key`,
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return decryptSecretsData(data as EncryptedSecretsFile, key);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Legacy: unencrypted format (for backwards compatibility)
|
|
157
|
-
return data as StageSecrets;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Write secrets for a stage (encrypted).
|
|
162
|
-
* Creates or uses existing encryption key at ~/.gkm/{project}/{stage}.key
|
|
163
|
-
*/
|
|
164
|
-
export async function writeStageSecrets(
|
|
165
|
-
secrets: StageSecrets,
|
|
166
|
-
cwd = process.cwd(),
|
|
167
|
-
): Promise<void> {
|
|
168
|
-
const dir = getSecretsDir(cwd);
|
|
169
|
-
const path = getSecretsPath(secrets.stage, cwd);
|
|
170
|
-
const projectName = basename(cwd);
|
|
171
|
-
|
|
172
|
-
// Ensure directory exists
|
|
173
|
-
await mkdir(dir, { recursive: true });
|
|
174
|
-
|
|
175
|
-
// Get or create encryption key
|
|
176
|
-
const key = await getOrCreateKey(secrets.stage, projectName);
|
|
177
|
-
|
|
178
|
-
// Encrypt and write
|
|
179
|
-
const encrypted = encryptSecretsData(secrets, key);
|
|
180
|
-
await writeFile(path, JSON.stringify(encrypted, null, 2), 'utf-8');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Convert StageSecrets to embeddable format (flat key-value pairs).
|
|
185
|
-
* This is what gets encrypted and embedded in the bundle.
|
|
186
|
-
*/
|
|
187
|
-
export function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {
|
|
188
|
-
return {
|
|
189
|
-
...secrets.urls,
|
|
190
|
-
...secrets.custom,
|
|
191
|
-
// Also include individual service credentials if needed
|
|
192
|
-
...(secrets.services.postgres && {
|
|
193
|
-
POSTGRES_USER: secrets.services.postgres.username,
|
|
194
|
-
POSTGRES_PASSWORD: secrets.services.postgres.password,
|
|
195
|
-
POSTGRES_DB: secrets.services.postgres.database ?? 'app',
|
|
196
|
-
POSTGRES_HOST: secrets.services.postgres.host,
|
|
197
|
-
POSTGRES_PORT: String(secrets.services.postgres.port),
|
|
198
|
-
}),
|
|
199
|
-
...(secrets.services.redis && {
|
|
200
|
-
REDIS_PASSWORD: secrets.services.redis.password,
|
|
201
|
-
REDIS_HOST: secrets.services.redis.host,
|
|
202
|
-
REDIS_PORT: String(secrets.services.redis.port),
|
|
203
|
-
}),
|
|
204
|
-
...(secrets.services.rabbitmq && {
|
|
205
|
-
RABBITMQ_USER: secrets.services.rabbitmq.username,
|
|
206
|
-
RABBITMQ_PASSWORD: secrets.services.rabbitmq.password,
|
|
207
|
-
RABBITMQ_HOST: secrets.services.rabbitmq.host,
|
|
208
|
-
RABBITMQ_PORT: String(secrets.services.rabbitmq.port),
|
|
209
|
-
RABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',
|
|
210
|
-
}),
|
|
211
|
-
...(secrets.services.minio && {
|
|
212
|
-
STORAGE_ACCESS_KEY_ID: secrets.services.minio.username,
|
|
213
|
-
STORAGE_SECRET_ACCESS_KEY: secrets.services.minio.password,
|
|
214
|
-
STORAGE_BUCKET: secrets.services.minio.bucket ?? 'app',
|
|
215
|
-
STORAGE_REGION: 'eu-west-1',
|
|
216
|
-
STORAGE_FORCE_PATH_STYLE: 'true',
|
|
217
|
-
}),
|
|
218
|
-
...(secrets.services.mailpit && {
|
|
219
|
-
SMTP_HOST: secrets.services.mailpit.host,
|
|
220
|
-
SMTP_PORT: String(secrets.services.mailpit.port),
|
|
221
|
-
SMTP_USER: secrets.services.mailpit.username,
|
|
222
|
-
SMTP_PASS: secrets.services.mailpit.password,
|
|
223
|
-
SMTP_SECURE: 'false',
|
|
224
|
-
MAIL_FROM: 'noreply@localhost',
|
|
225
|
-
}),
|
|
226
|
-
...(secrets.services.localstack && {
|
|
227
|
-
AWS_ACCESS_KEY_ID:
|
|
228
|
-
secrets.services.localstack.accessKeyId ??
|
|
229
|
-
secrets.services.localstack.username,
|
|
230
|
-
AWS_SECRET_ACCESS_KEY: secrets.services.localstack.password,
|
|
231
|
-
AWS_REGION: secrets.services.localstack.region ?? 'us-east-1',
|
|
232
|
-
AWS_ENDPOINT_URL: `http://${secrets.services.localstack.host}:${secrets.services.localstack.port}`,
|
|
233
|
-
}),
|
|
234
|
-
...(secrets.services.pgboss && {
|
|
235
|
-
PGBOSS_DB_USER: secrets.services.pgboss.username,
|
|
236
|
-
PGBOSS_DB_PASSWORD: secrets.services.pgboss.password,
|
|
237
|
-
}),
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Update a custom secret in the secrets file.
|
|
243
|
-
*/
|
|
244
|
-
export async function setCustomSecret(
|
|
245
|
-
stage: string,
|
|
246
|
-
key: string,
|
|
247
|
-
value: string,
|
|
248
|
-
cwd = process.cwd(),
|
|
249
|
-
): Promise<StageSecrets> {
|
|
250
|
-
const secrets = await readStageSecrets(stage, cwd);
|
|
251
|
-
|
|
252
|
-
if (!secrets) {
|
|
253
|
-
throw new Error(
|
|
254
|
-
`Secrets not found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const updated: StageSecrets = {
|
|
259
|
-
...secrets,
|
|
260
|
-
updatedAt: new Date().toISOString(),
|
|
261
|
-
custom: {
|
|
262
|
-
...secrets.custom,
|
|
263
|
-
[key]: value,
|
|
264
|
-
},
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
await writeStageSecrets(updated, cwd);
|
|
268
|
-
return updated;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Mask a password for display (show first 4 and last 2 chars).
|
|
273
|
-
*/
|
|
274
|
-
export function maskPassword(password: string): string {
|
|
275
|
-
if (password.length <= 8) {
|
|
276
|
-
return '********';
|
|
277
|
-
}
|
|
278
|
-
return `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Result of environment variable validation.
|
|
283
|
-
*/
|
|
284
|
-
export interface EnvValidationResult {
|
|
285
|
-
/** Whether all required environment variables are present */
|
|
286
|
-
valid: boolean;
|
|
287
|
-
/** List of missing environment variable names */
|
|
288
|
-
missing: string[];
|
|
289
|
-
/** List of environment variables that are provided */
|
|
290
|
-
provided: string[];
|
|
291
|
-
/** List of environment variables that were required */
|
|
292
|
-
required: string[];
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Validate that all required environment variables are present in secrets.
|
|
297
|
-
*
|
|
298
|
-
* @param requiredVars - Array of environment variable names required by the application
|
|
299
|
-
* @param secrets - Stage secrets to validate against
|
|
300
|
-
* @returns Validation result with missing and provided variables
|
|
301
|
-
*
|
|
302
|
-
* @example
|
|
303
|
-
* ```typescript
|
|
304
|
-
* const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
|
|
305
|
-
* const secrets = await readStageSecrets('production');
|
|
306
|
-
* const result = validateEnvironmentVariables(required, secrets);
|
|
307
|
-
*
|
|
308
|
-
* if (!result.valid) {
|
|
309
|
-
* console.error(`Missing environment variables: ${result.missing.join(', ')}`);
|
|
310
|
-
* }
|
|
311
|
-
* ```
|
|
312
|
-
*/
|
|
313
|
-
export function validateEnvironmentVariables(
|
|
314
|
-
requiredVars: string[],
|
|
315
|
-
secrets: StageSecrets,
|
|
316
|
-
): EnvValidationResult {
|
|
317
|
-
const embeddable = toEmbeddableSecrets(secrets);
|
|
318
|
-
const availableVars = new Set(Object.keys(embeddable));
|
|
319
|
-
|
|
320
|
-
const missing: string[] = [];
|
|
321
|
-
const provided: string[] = [];
|
|
322
|
-
|
|
323
|
-
for (const varName of requiredVars) {
|
|
324
|
-
if (availableVars.has(varName)) {
|
|
325
|
-
provided.push(varName);
|
|
326
|
-
} else {
|
|
327
|
-
missing.push(varName);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return {
|
|
332
|
-
valid: missing.length === 0,
|
|
333
|
-
missing: missing.sort(),
|
|
334
|
-
provided: provided.sort(),
|
|
335
|
-
required: [...requiredVars].sort(),
|
|
336
|
-
};
|
|
337
|
-
}
|
package/src/secrets/sync.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Secrets Sync via AWS SSM Parameter Store
|
|
3
|
-
*
|
|
4
|
-
* Stores and retrieves encrypted StageSecrets as SecureString parameters.
|
|
5
|
-
* Reuses the SSM infrastructure from the state provider.
|
|
6
|
-
*
|
|
7
|
-
* Parameter naming: /gkm/{workspaceName}/{stage}/secrets
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
GetParameterCommand,
|
|
12
|
-
ParameterNotFound,
|
|
13
|
-
PutParameterCommand,
|
|
14
|
-
SSMClient,
|
|
15
|
-
type SSMClientConfig,
|
|
16
|
-
} from '@aws-sdk/client-ssm';
|
|
17
|
-
import type { SSMStateConfig } from '../deploy/StateProvider.js';
|
|
18
|
-
import type { NormalizedWorkspace } from '../workspace/types.js';
|
|
19
|
-
import type { StageSecrets } from './types.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get the SSM parameter name for secrets.
|
|
23
|
-
*/
|
|
24
|
-
function getSecretsParameterName(workspaceName: string, stage: string): string {
|
|
25
|
-
return `/gkm/${workspaceName}/${stage}/secrets`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Create an SSM client from workspace state config.
|
|
30
|
-
*/
|
|
31
|
-
function createSSMClient(config: SSMStateConfig): SSMClient {
|
|
32
|
-
const clientConfig: SSMClientConfig = {
|
|
33
|
-
region: config.region,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
if (config.profile) {
|
|
37
|
-
const { fromIni } = require('@aws-sdk/credential-providers');
|
|
38
|
-
clientConfig.credentials = fromIni({ profile: config.profile });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return new SSMClient(clientConfig);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Push secrets to SSM Parameter Store.
|
|
46
|
-
*
|
|
47
|
-
* Stores the full StageSecrets object as a SecureString parameter.
|
|
48
|
-
*/
|
|
49
|
-
export async function pushSecrets(
|
|
50
|
-
stage: string,
|
|
51
|
-
workspace: NormalizedWorkspace,
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
const config = workspace.state;
|
|
54
|
-
if (!config || config.provider !== 'ssm') {
|
|
55
|
-
throw new Error(
|
|
56
|
-
'SSM state provider not configured. Add state: { provider: "ssm", region: "..." } to gkm.config.ts.',
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!workspace.name) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
'Workspace name is required for SSM secrets sync. Set "name" in gkm.config.ts.',
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const client = createSSMClient(config as SSMStateConfig);
|
|
67
|
-
const parameterName = getSecretsParameterName(workspace.name, stage);
|
|
68
|
-
|
|
69
|
-
const { readStageSecrets } = await import('./storage.js');
|
|
70
|
-
const secrets = await readStageSecrets(stage, workspace.root);
|
|
71
|
-
|
|
72
|
-
if (!secrets) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
await client.send(
|
|
79
|
-
new PutParameterCommand({
|
|
80
|
-
Name: parameterName,
|
|
81
|
-
Value: JSON.stringify(secrets),
|
|
82
|
-
Type: 'SecureString',
|
|
83
|
-
Overwrite: true,
|
|
84
|
-
Description: `GKM secrets for ${workspace.name}/${stage}`,
|
|
85
|
-
}),
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Pull secrets from SSM Parameter Store.
|
|
91
|
-
*
|
|
92
|
-
* @returns StageSecrets or null if no secrets are stored remotely
|
|
93
|
-
*/
|
|
94
|
-
export async function pullSecrets(
|
|
95
|
-
stage: string,
|
|
96
|
-
workspace: NormalizedWorkspace,
|
|
97
|
-
): Promise<StageSecrets | null> {
|
|
98
|
-
const config = workspace.state;
|
|
99
|
-
if (!config || config.provider !== 'ssm') {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!workspace.name) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const client = createSSMClient(config as SSMStateConfig);
|
|
108
|
-
const parameterName = getSecretsParameterName(workspace.name, stage);
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const response = await client.send(
|
|
112
|
-
new GetParameterCommand({
|
|
113
|
-
Name: parameterName,
|
|
114
|
-
WithDecryption: true,
|
|
115
|
-
}),
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
if (!response.Parameter?.Value) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return JSON.parse(response.Parameter.Value) as StageSecrets;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
if (error instanceof ParameterNotFound) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
throw error;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Check if SSM is configured for the workspace.
|
|
133
|
-
*/
|
|
134
|
-
export function isSSMConfigured(workspace: NormalizedWorkspace): boolean {
|
|
135
|
-
return !!workspace.state && workspace.state.provider === 'ssm';
|
|
136
|
-
}
|
package/src/secrets/types.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { ComposeServiceName, EventsBackend } from '../types';
|
|
2
|
-
|
|
3
|
-
/** Credentials for a specific service */
|
|
4
|
-
export interface ServiceCredentials {
|
|
5
|
-
host: string;
|
|
6
|
-
port: number;
|
|
7
|
-
username: string;
|
|
8
|
-
password: string;
|
|
9
|
-
/** Database name (for postgres) */
|
|
10
|
-
database?: string;
|
|
11
|
-
/** Virtual host (for rabbitmq) */
|
|
12
|
-
vhost?: string;
|
|
13
|
-
/** Bucket name (for minio) */
|
|
14
|
-
bucket?: string;
|
|
15
|
-
/** Access key ID (for localstack) */
|
|
16
|
-
accessKeyId?: string;
|
|
17
|
-
/** Region (for localstack) */
|
|
18
|
-
region?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Stage secrets configuration */
|
|
22
|
-
export interface StageSecrets {
|
|
23
|
-
/** Stage name (e.g., 'production', 'staging') */
|
|
24
|
-
stage: string;
|
|
25
|
-
/** ISO timestamp when secrets were created */
|
|
26
|
-
createdAt: string;
|
|
27
|
-
/** ISO timestamp when secrets were last updated */
|
|
28
|
-
updatedAt: string;
|
|
29
|
-
/** Event backend type (if events are enabled) */
|
|
30
|
-
eventsBackend?: EventsBackend;
|
|
31
|
-
/** Service-specific credentials */
|
|
32
|
-
services: {
|
|
33
|
-
postgres?: ServiceCredentials;
|
|
34
|
-
redis?: ServiceCredentials;
|
|
35
|
-
rabbitmq?: ServiceCredentials;
|
|
36
|
-
minio?: ServiceCredentials;
|
|
37
|
-
mailpit?: ServiceCredentials;
|
|
38
|
-
localstack?: ServiceCredentials;
|
|
39
|
-
pgboss?: ServiceCredentials;
|
|
40
|
-
};
|
|
41
|
-
/** Generated connection URLs */
|
|
42
|
-
urls: {
|
|
43
|
-
DATABASE_URL?: string;
|
|
44
|
-
REDIS_URL?: string;
|
|
45
|
-
RABBITMQ_URL?: string;
|
|
46
|
-
STORAGE_ENDPOINT?: string;
|
|
47
|
-
SMTP_HOST?: string;
|
|
48
|
-
SMTP_PORT?: string;
|
|
49
|
-
EVENT_PUBLISHER_CONNECTION_STRING?: string;
|
|
50
|
-
EVENT_SUBSCRIBER_CONNECTION_STRING?: string;
|
|
51
|
-
};
|
|
52
|
-
/** Custom user-defined secrets */
|
|
53
|
-
custom: Record<string, string>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Encrypted payload for build-time injection */
|
|
57
|
-
export interface EncryptedPayload {
|
|
58
|
-
/** Base64 encoded encrypted data (ciphertext + auth tag) */
|
|
59
|
-
encrypted: string;
|
|
60
|
-
/** Hex encoded IV */
|
|
61
|
-
iv: string;
|
|
62
|
-
/** Hex encoded ephemeral master key (for deployment) */
|
|
63
|
-
masterKey: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Secrets that get encrypted and embedded in the bundle */
|
|
67
|
-
export type EmbeddableSecrets = Record<string, string>;
|
|
68
|
-
|
|
69
|
-
/** Services that support automatic credential generation */
|
|
70
|
-
export type SecretServiceName = ComposeServiceName;
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { rm } from 'node:fs/promises';
|
|
3
|
-
import { homedir, tmpdir } from 'node:os';
|
|
4
|
-
import { basename, join } from 'node:path';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
|
-
import { readStageSecrets, secretsExist } from '../../secrets/storage.js';
|
|
7
|
-
import type { NormalizedWorkspace } from '../../workspace/types.js';
|
|
8
|
-
import { createFreshWorkspaceSecrets, ensureStageSecrets } from '../index.js';
|
|
9
|
-
|
|
10
|
-
function createWorkspace(
|
|
11
|
-
overrides: Partial<NormalizedWorkspace> = {},
|
|
12
|
-
): NormalizedWorkspace {
|
|
13
|
-
return {
|
|
14
|
-
name: 'test-project',
|
|
15
|
-
root: '/tmp/test-project',
|
|
16
|
-
apps: {
|
|
17
|
-
api: {
|
|
18
|
-
type: 'backend',
|
|
19
|
-
port: 3000,
|
|
20
|
-
root: '/tmp/test-project/apps/api',
|
|
21
|
-
packageName: '@test/api',
|
|
22
|
-
routes: './src/endpoints/**/*.ts',
|
|
23
|
-
dependencies: [],
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
services: { db: true },
|
|
27
|
-
deploy: {},
|
|
28
|
-
shared: {},
|
|
29
|
-
secrets: {},
|
|
30
|
-
...overrides,
|
|
31
|
-
} as NormalizedWorkspace;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe('createFreshWorkspaceSecrets', () => {
|
|
35
|
-
it('generates postgres credentials when db service is enabled', () => {
|
|
36
|
-
const secrets = createFreshWorkspaceSecrets(
|
|
37
|
-
'development',
|
|
38
|
-
createWorkspace(),
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
expect(secrets.stage).toBe('development');
|
|
42
|
-
expect(secrets.services.postgres).toBeDefined();
|
|
43
|
-
expect(secrets.services.postgres?.password).toBeTruthy();
|
|
44
|
-
expect(secrets.urls.DATABASE_URL).toContain('postgresql://');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('generates a randomized password each call', () => {
|
|
48
|
-
const a = createFreshWorkspaceSecrets('development', createWorkspace());
|
|
49
|
-
const b = createFreshWorkspaceSecrets('development', createWorkspace());
|
|
50
|
-
|
|
51
|
-
expect(a.services.postgres?.password).not.toBe(
|
|
52
|
-
b.services.postgres?.password,
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('adds single-app custom secrets', () => {
|
|
57
|
-
const secrets = createFreshWorkspaceSecrets(
|
|
58
|
-
'development',
|
|
59
|
-
createWorkspace(),
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
expect(secrets.custom.NODE_ENV).toBe('development');
|
|
63
|
-
expect(secrets.custom.JWT_SECRET).toBeTruthy();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('ensureStageSecrets', () => {
|
|
68
|
-
let testDir: string;
|
|
69
|
-
const originalGkmConfigPath = process.env.GKM_CONFIG_PATH;
|
|
70
|
-
|
|
71
|
-
beforeEach(() => {
|
|
72
|
-
testDir = join(
|
|
73
|
-
tmpdir(),
|
|
74
|
-
`gkm-auto-setup-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
75
|
-
);
|
|
76
|
-
mkdirSync(testDir, { recursive: true });
|
|
77
|
-
|
|
78
|
-
// Minimal single-app workspace config with a db service.
|
|
79
|
-
writeFileSync(
|
|
80
|
-
join(testDir, 'gkm.config.ts'),
|
|
81
|
-
`import { defineWorkspace } from '@geekmidas/cli/config';
|
|
82
|
-
|
|
83
|
-
export default defineWorkspace({
|
|
84
|
-
name: 'test-workspace',
|
|
85
|
-
apps: {
|
|
86
|
-
api: {
|
|
87
|
-
type: 'backend',
|
|
88
|
-
path: 'apps/api',
|
|
89
|
-
port: 3001,
|
|
90
|
-
routes: './src/endpoints/**/*.ts',
|
|
91
|
-
envParser: './src/config/env#envParser',
|
|
92
|
-
logger: './src/config/logger#logger',
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
services: { db: true },
|
|
96
|
-
});
|
|
97
|
-
`,
|
|
98
|
-
);
|
|
99
|
-
const apiDir = join(testDir, 'apps', 'api');
|
|
100
|
-
mkdirSync(apiDir, { recursive: true });
|
|
101
|
-
writeFileSync(
|
|
102
|
-
join(apiDir, 'package.json'),
|
|
103
|
-
JSON.stringify({ name: '@test/api', version: '0.0.1' }),
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
process.env.GKM_CONFIG_PATH = join(testDir, 'gkm.config.ts');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
afterEach(async () => {
|
|
110
|
-
if (originalGkmConfigPath === undefined) {
|
|
111
|
-
delete process.env.GKM_CONFIG_PATH;
|
|
112
|
-
} else {
|
|
113
|
-
process.env.GKM_CONFIG_PATH = originalGkmConfigPath;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
await rm(testDir, { recursive: true, force: true });
|
|
117
|
-
// writeStageSecrets mints a key at ~/.gkm/{basename(root)}
|
|
118
|
-
await rm(join(homedir(), '.gkm', basename(testDir)), {
|
|
119
|
-
recursive: true,
|
|
120
|
-
force: true,
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('generates a decryptable stage when none exists', async () => {
|
|
125
|
-
expect(secretsExist('development', testDir)).toBe(false);
|
|
126
|
-
|
|
127
|
-
const generated = await ensureStageSecrets('development', testDir);
|
|
128
|
-
|
|
129
|
-
expect(generated).toBe(true);
|
|
130
|
-
expect(secretsExist('development', testDir)).toBe(true);
|
|
131
|
-
|
|
132
|
-
// Round-trips through the keystore the same way `gkm test` reads it.
|
|
133
|
-
const read = await readStageSecrets('development', testDir);
|
|
134
|
-
expect(read?.services.postgres).toBeDefined();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('is a no-op when secrets already exist', async () => {
|
|
138
|
-
await ensureStageSecrets('development', testDir);
|
|
139
|
-
const before = await readStageSecrets('development', testDir);
|
|
140
|
-
|
|
141
|
-
const generated = await ensureStageSecrets('development', testDir);
|
|
142
|
-
|
|
143
|
-
expect(generated).toBe(false);
|
|
144
|
-
const after = await readStageSecrets('development', testDir);
|
|
145
|
-
expect(after).toEqual(before);
|
|
146
|
-
});
|
|
147
|
-
});
|