@geekmidas/cli 10.0.0-alpha.112 → 10.0.0-alpha.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -51,7 +51,7 @@ import crypto from "crypto";
51
51
  import { Function } from "@geekmidas/constructs/functions";
52
52
  import { Topic } from "@geekmidas/constructs/topic";
53
53
  //#region package.json
54
- var version = "10.0.0-alpha.112";
54
+ var version = "10.0.0-alpha.114";
55
55
  //#endregion
56
56
  //#region src/prompt.ts
57
57
  /**
@@ -5943,25 +5943,25 @@ function loadPackageJson() {
5943
5943
  * Run: pnpm --filter @geekmidas/cli sync-versions
5944
5944
  */
5945
5945
  const GEEKMIDAS_VERSIONS = {
5946
- "@geekmidas/audit": "~10.0.0-alpha.112",
5947
- "@geekmidas/auth": "~10.0.0-alpha.112",
5948
- "@geekmidas/cache": "~10.0.0-alpha.112",
5949
- "@geekmidas/client": "~10.0.0-alpha.112",
5950
- "@geekmidas/cloud": "~10.0.0-alpha.112",
5951
- "@geekmidas/constructs": "~10.0.0-alpha.112",
5952
- "@geekmidas/db": "~10.0.0-alpha.112",
5953
- "@geekmidas/emailkit": "~10.0.0-alpha.112",
5954
- "@geekmidas/envkit": "~10.0.0-alpha.112",
5955
- "@geekmidas/errors": "~10.0.0-alpha.112",
5956
- "@geekmidas/events": "~10.0.0-alpha.112",
5957
- "@geekmidas/logger": "~10.0.0-alpha.112",
5958
- "@geekmidas/manifest": "~10.0.0-alpha.112",
5959
- "@geekmidas/rate-limit": "~10.0.0-alpha.112",
5960
- "@geekmidas/schema": "~10.0.0-alpha.112",
5961
- "@geekmidas/services": "~10.0.0-alpha.112",
5962
- "@geekmidas/storage": "~10.0.0-alpha.112",
5963
- "@geekmidas/telescope": "~10.0.0-alpha.112",
5964
- "@geekmidas/testkit": "~10.0.0-alpha.112",
5946
+ "@geekmidas/audit": "~10.0.0-alpha.114",
5947
+ "@geekmidas/auth": "~10.0.0-alpha.114",
5948
+ "@geekmidas/cache": "~10.0.0-alpha.114",
5949
+ "@geekmidas/client": "~10.0.0-alpha.114",
5950
+ "@geekmidas/cloud": "~10.0.0-alpha.114",
5951
+ "@geekmidas/constructs": "~10.0.0-alpha.114",
5952
+ "@geekmidas/db": "~10.0.0-alpha.114",
5953
+ "@geekmidas/emailkit": "~10.0.0-alpha.114",
5954
+ "@geekmidas/envkit": "~10.0.0-alpha.114",
5955
+ "@geekmidas/errors": "~10.0.0-alpha.114",
5956
+ "@geekmidas/events": "~10.0.0-alpha.114",
5957
+ "@geekmidas/logger": "~10.0.0-alpha.114",
5958
+ "@geekmidas/manifest": "~10.0.0-alpha.114",
5959
+ "@geekmidas/rate-limit": "~10.0.0-alpha.114",
5960
+ "@geekmidas/schema": "~10.0.0-alpha.114",
5961
+ "@geekmidas/services": "~10.0.0-alpha.114",
5962
+ "@geekmidas/storage": "~10.0.0-alpha.114",
5963
+ "@geekmidas/telescope": "~10.0.0-alpha.114",
5964
+ "@geekmidas/testkit": "~10.0.0-alpha.114",
5965
5965
  "@geekmidas/cli": `~${loadPackageJson().version}`
5966
5966
  };
5967
5967
  //#endregion
@@ -7154,7 +7154,7 @@ const COMMIT = /^[0-9a-f]{40}$/;
7154
7154
  * The `uses:` value for the stages action, with a comment saying which CLI
7155
7155
  * release the pinned commit is.
7156
7156
  */
7157
- function stagesActionUses(commit = "4f82632d8355cb858b895c3caf36228e040d39b0", version = cliVersion()) {
7157
+ function stagesActionUses(commit = "82e87263a7c554204b12819f4eff2c4f7e9c8a96", version = cliVersion()) {
7158
7158
  return commit && COMMIT.test(commit) ? `${STAGES_ACTION}@${commit} # @geekmidas/cli ${version}` : `${STAGES_ACTION}@main # pin to a commit SHA: see the action's README`;
7159
7159
  }
7160
7160
  //#endregion
@@ -7406,6 +7406,7 @@ function stagesJob(options) {
7406
7406
  has-build: \${{ steps.stages.outputs.has-build }}
7407
7407
  has-deploy: \${{ steps.stages.outputs.has-deploy }}
7408
7408
  aws-region: \${{ steps.stages.outputs.aws-region }}
7409
+ registry: \${{ steps.stages.outputs.registry }}
7409
7410
  steps:
7410
7411
  - uses: actions/checkout@v4
7411
7412
 
@@ -7424,17 +7425,25 @@ ${pm.setup}
7424
7425
  `;
7425
7426
  }
7426
7427
  /**
7427
- * The registry login a compose build pushes with: GitHub's own token on
7428
- * ghcr.io, otherwise a username variable and a password secret.
7428
+ * The registry login a compose build pushes with, and a deploy pulls with.
7429
+ * The host is `deploy.registry`'s, read from gkm.config.ts by the stages
7430
+ * job at run time — never written here, so the workflow follows the config:
7431
+ * GitHub's own token on ghcr.io, otherwise the stage environment's
7432
+ * `REGISTRY_USERNAME` variable and `REGISTRY_PASSWORD` secret.
7429
7433
  */
7430
- function registryLogin(registry) {
7431
- const host = registry.split("/")[0];
7432
- const ghcr = host === "ghcr.io";
7433
- return ` - uses: docker/login-action@v3
7434
+ function registryLogin() {
7435
+ const ghcr = "needs.stages.outputs.registry == 'ghcr.io'";
7436
+ return ` # deploy.registry in gkm.config.ts: GitHub's registry with this
7437
+ # workflow's own token (the job's \`packages\` permission decides push
7438
+ # or pull), any other with the stage's REGISTRY_USERNAME variable and
7439
+ # REGISTRY_PASSWORD secret.
7440
+ - name: Log in to the registry
7441
+ if: needs.stages.outputs.registry != ''
7442
+ uses: docker/login-action@v3
7434
7443
  with:
7435
- registry: ${host}
7436
- username: ${ghcr ? "${{ github.actor }}" : "${{ vars.REGISTRY_USERNAME }}"}
7437
- password: ${ghcr ? "${{ secrets.GITHUB_TOKEN }}" : "${{ secrets.REGISTRY_PASSWORD }}"}
7444
+ registry: \${{ needs.stages.outputs.registry }}
7445
+ username: \${{ ${ghcr} && github.actor || vars.REGISTRY_USERNAME }}
7446
+ password: \${{ ${ghcr} && secrets.GITHUB_TOKEN || secrets.REGISTRY_PASSWORD }}
7438
7447
  `;
7439
7448
  }
7440
7449
  /**
@@ -7453,8 +7462,14 @@ function registryLogin(registry) {
7453
7462
  */
7454
7463
  function composeDeploy(options) {
7455
7464
  const pm = tooling(options);
7456
- const registry = options.registry ?? "";
7457
7465
  return `${deployHeader(true)}
7466
+ # A push to main builds main's newest commit: a later push cancels an earlier
7467
+ # push's run, so several merges in a row build once. A release or a manual
7468
+ # run shares no group (its run id is in the name), and is never cancelled.
7469
+ concurrency:
7470
+ group: \${{ github.workflow }}-\${{ github.event_name == 'push' && github.ref || github.run_id }}
7471
+ cancel-in-progress: \${{ github.event_name == 'push' }}
7472
+
7458
7473
  jobs:
7459
7474
  ${stagesJob(options)}
7460
7475
  build:
@@ -7473,13 +7488,22 @@ ${stagesJob(options)}
7473
7488
  packages: write
7474
7489
  id-token: write
7475
7490
  steps:
7491
+ # The runner's preinstalled toolchains, none of them used here: with
7492
+ # them, building every image of a workspace runs out of disk.
7493
+ - name: Free disk space
7494
+ run: |
7495
+ sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \\
7496
+ /usr/local/.ghcup /opt/hostedtoolcache/CodeQL
7497
+ sudo docker image prune --all --force
7498
+ df -h /
7499
+
7476
7500
  - uses: actions/checkout@v4
7477
7501
 
7478
7502
  ${pm.setup}
7479
7503
  - name: Install
7480
7504
  run: ${pm.install}
7481
7505
 
7482
- ${registryLogin(registry)}
7506
+ ${registryLogin()}
7483
7507
  # A site's public URLs are built into it, so the build reads the stage's
7484
7508
  # secrets store. With secrets.store on S3, SSM or Secrets Manager the job
7485
7509
  # assumes the stage's role (AWS_ROLE_ARN, set by gkm deploy:github);
@@ -7505,6 +7529,7 @@ ${registryLogin(registry)}
7505
7529
  with:
7506
7530
  name: digests-\${{ matrix.stage }}
7507
7531
  path: digests.json
7532
+ if-no-files-found: error
7508
7533
  retention-days: 90
7509
7534
 
7510
7535
  deploy:
@@ -7538,8 +7563,14 @@ ${registryLogin(registry)}
7538
7563
  workflow_dispatch) ref="\${REF:-$SHA}" ;;
7539
7564
  *) ref="$SHA" ;;
7540
7565
  esac
7541
- sha=$(gh api "repos/$REPO/commits/$ref" --jq .sha)
7542
- echo "Deploying $sha"
7566
+ case "$ref" in
7567
+ ''|-*) echo "::error::Not a tag or commit: '$ref'"; exit 1 ;;
7568
+ esac
7569
+ if ! sha=$(gh api "repos/$REPO/commits/$ref" --jq .sha); then
7570
+ echo "::error::'$ref' is not a tag, branch or commit in this repository"
7571
+ exit 1
7572
+ fi
7573
+ echo "Deploying $ref = $sha"
7543
7574
  echo "sha=$sha" >> "$GITHUB_OUTPUT"
7544
7575
  env:
7545
7576
  GH_TOKEN: \${{ github.token }}
@@ -7560,7 +7591,7 @@ ${pm.setup}
7560
7591
 
7561
7592
  # The server's engine pulls with the login docker sends from here: it
7562
7593
  # holds none of its own.
7563
- ${registryLogin(registry)}
7594
+ ${registryLogin()}
7564
7595
  # The stage's secrets and deploy state are read and written here, with
7565
7596
  # the stage's role (AWS_ROLE_ARN, set by gkm deploy:github). With the
7566
7597
  # default 'file' secrets store there is no role, and no secrets file in
@@ -7621,6 +7652,7 @@ ${registryLogin(registry)}
7621
7652
  # pinned host key (DEPLOY_KNOWN_HOSTS, a variable) on each environment:
7622
7653
  # never accepted on first sight. The server — user and host — is
7623
7654
  # deploy.compose.server in gkm.config.ts and the stage's GKM_SERVER_IPV4.
7655
+ # \`gkm compose:server --stage <stage>\` sets the server up and gives both.
7624
7656
  - name: SSH to the server
7625
7657
  run: |
7626
7658
  mkdir -p ~/.ssh && chmod 700 ~/.ssh
@@ -13039,6 +13071,7 @@ export default function RootLayout({
13039
13071
  `;
13040
13072
  const pages = app.key === "admin" ? adminPages() : webPages(options);
13041
13073
  const gitignore = `.next/
13074
+ next-env.d.ts
13042
13075
  node_modules/
13043
13076
  .env.local
13044
13077
  *.log
@@ -16714,6 +16747,16 @@ program.command("deploy:rollback").description("Put a stage's app back on its pr
16714
16747
  exitWithError(error);
16715
16748
  }
16716
16749
  });
16750
+ program.command("compose:server").description("Set up a stage's server for compose deploys: harden it (SSH keys only, no root login, firewall, security updates, fail2ban), install Docker, create the deploy user, and give its key to GitHub").requiredOption("--stage <stage>", "A deployed stage from gkm.config.ts").option("--admin <user>", "The sudo user you log in to the server as — never root (asked when absent)").option("--key-file <path>", "The deploy key pair (default: ~/.ssh/gkm-<project>-<stage>)").option("--repo <owner/name>", "GitHub repository (default: this one)").option("--no-github", "Leave the GitHub environment's key and host alone").option("--yes", "Set the server up without asking first").option("--dry-run", "Print the plan and the script; connect to nothing").action(async (options) => {
16751
+ try {
16752
+ const globalOptions = program.opts();
16753
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16754
+ const { composeServerCommand } = await import("./serverSetup--O61SRvg.mjs");
16755
+ await composeServerCommand(options);
16756
+ } catch (error) {
16757
+ exitWithError(error);
16758
+ }
16759
+ });
16717
16760
  program.command("deploy:init").description("Initialize Dokploy deployment (create project and application)").option("--endpoint <url>", "Dokploy server URL (uses stored credentials if logged in)").requiredOption("--project <name>", "Project name (creates if not exists)").requiredOption("--app <name>", "Application name").option("--project-id <id>", "Use existing project ID instead of creating").option("--registry-id <id>", "Configure registry for the application").action(async (options) => {
16718
16761
  try {
16719
16762
  const globalOptions = program.opts();
@@ -16733,7 +16776,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16733
16776
  try {
16734
16777
  const globalOptions = program.opts();
16735
16778
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16736
- const { deployGithubCommand } = await import("./github-D2eABlxM.mjs");
16779
+ const { deployGithubCommand } = await import("./github-BMakI-k3.mjs");
16737
16780
  await deployGithubCommand(options);
16738
16781
  } catch (error) {
16739
16782
  exitWithError(error);
@@ -16743,7 +16786,7 @@ program.command("stages").description("The workspace's stages from gkm.config.ts
16743
16786
  try {
16744
16787
  const globalOptions = program.opts();
16745
16788
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16746
- const { stagesCommand } = await import("./stages-DJrOYLZ-.mjs");
16789
+ const { stagesCommand } = await import("./stages-Cb9rqRbN.mjs");
16747
16790
  await stagesCommand(options);
16748
16791
  } catch (error) {
16749
16792
  exitWithError(error);