grada-run 0.0.2 → 0.32.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/.github/workflows/deploy-docs.yml +37 -0
- package/.github/workflows/iac-validation.yml +303 -0
- package/.github/workflows/publish.yml +68 -0
- package/.github/workflows/sync-bedrock-models.yml +57 -0
- package/.github/workflows/test.yml +43 -0
- package/.muserules +31 -0
- package/LICENSE +21 -0
- package/README.md +193 -3
- package/apps/docs/.astro/collections/docs.schema.json +644 -0
- package/apps/docs/.astro/content-assets.mjs +4 -0
- package/apps/docs/.astro/content-modules.mjs +4 -0
- package/apps/docs/.astro/content.d.ts +179 -0
- package/apps/docs/.astro/data-store.json +1 -0
- package/apps/docs/.astro/dev.json +14 -0
- package/apps/docs/.astro/settings.json +5 -0
- package/apps/docs/.astro/types.d.ts +2 -0
- package/apps/docs/astro.config.mjs +97 -0
- package/apps/docs/package.json +17 -0
- package/apps/docs/src/content/docs/adrs/0001-s3-native-state-locking.md +37 -0
- package/apps/docs/src/content/docs/adrs/0002-eject-mechanism-pure-iac.md +39 -0
- package/apps/docs/src/content/docs/adrs/0003-sync-ai-context-strategy.md +48 -0
- package/apps/docs/src/content/docs/adrs/0004-iac-driven-diagnostic-context.md +37 -0
- package/apps/docs/src/content/docs/adrs/0005-ecs-fargate-alb-runtime-target.md +38 -0
- package/apps/docs/src/content/docs/adrs/0006-github-oidc-no-stored-keys.md +37 -0
- package/apps/docs/src/content/docs/adrs/0007-framework-detection-with-fallback.md +37 -0
- package/apps/docs/src/content/docs/adrs/0008-secrets-names-in-git-values-in-aws.md +37 -0
- package/apps/docs/src/content/docs/adrs/0009-regenerate-with-backup-on-rerun.md +37 -0
- package/apps/docs/src/content/docs/adrs/0010-advisory-only-security-scans.md +37 -0
- package/apps/docs/src/content/docs/cli/add.md +84 -0
- package/apps/docs/src/content/docs/cli/apply.md +32 -0
- package/apps/docs/src/content/docs/cli/db.md +200 -0
- package/apps/docs/src/content/docs/cli/destroy.md +31 -0
- package/apps/docs/src/content/docs/cli/diagnose.md +37 -0
- package/apps/docs/src/content/docs/cli/doctor.md +28 -0
- package/apps/docs/src/content/docs/cli/domain.md +57 -0
- package/apps/docs/src/content/docs/cli/drift.md +40 -0
- package/apps/docs/src/content/docs/cli/eject.md +29 -0
- package/apps/docs/src/content/docs/cli/exec.md +49 -0
- package/apps/docs/src/content/docs/cli/gc.md +37 -0
- package/apps/docs/src/content/docs/cli/init.md +72 -0
- package/apps/docs/src/content/docs/cli/logs.md +39 -0
- package/apps/docs/src/content/docs/cli/rollback.md +51 -0
- package/apps/docs/src/content/docs/cli/secrets.md +73 -0
- package/apps/docs/src/content/docs/cli/sleep.md +53 -0
- package/apps/docs/src/content/docs/cli/status.md +34 -0
- package/apps/docs/src/content/docs/cli/sync-ai.md +27 -0
- package/apps/docs/src/content/docs/guides/architecture.md +87 -0
- package/apps/docs/src/content/docs/guides/aws-credentials.md +72 -0
- package/apps/docs/src/content/docs/guides/background-workers.md +45 -0
- package/apps/docs/src/content/docs/guides/cicd-pipeline.md +64 -0
- package/apps/docs/src/content/docs/guides/database-connections.md +64 -0
- package/apps/docs/src/content/docs/guides/docker-compose.md +37 -0
- package/apps/docs/src/content/docs/guides/dockerfiles.md +46 -0
- package/apps/docs/src/content/docs/guides/ephemeral-pr-previews.md +39 -0
- package/apps/docs/src/content/docs/guides/examples.md +50 -0
- package/apps/docs/src/content/docs/guides/frameworks.md +88 -0
- package/apps/docs/src/content/docs/guides/headless.md +75 -0
- package/apps/docs/src/content/docs/guides/quickstart.md +52 -0
- package/apps/docs/src/content/docs/guides/rerun-init.md +43 -0
- package/apps/docs/src/content/docs/guides/secrets-management.md +83 -0
- package/apps/docs/src/content/docs/guides/understanding-your-bill.md +63 -0
- package/apps/docs/src/content/docs/index.mdx +103 -0
- package/apps/docs/src/content/docs/migrations/astro-vercel-to-aws.md +55 -0
- package/apps/docs/src/content/docs/migrations/heroku-procfile-to-aws.md +41 -0
- package/apps/docs/src/content/docs/migrations/nextjs-vercel-to-aws.md +51 -0
- package/apps/docs/src/content/docs/migrations/sveltekit-vercel-to-aws.md +63 -0
- package/apps/docs/src/content/docs/roadmap.md +97 -0
- package/apps/docs/src/content/docs/testing-strategy.md +32 -0
- package/apps/docs/src/content.config.ts +7 -0
- package/apps/docs/src/custom.css +14 -0
- package/apps/docs/tsconfig.json +6 -0
- package/bin/cli.js +140 -0
- package/package.json +105 -7
- package/scripts/sync-bedrock-models.js +22 -0
- package/scripts/test-iac.js +261 -0
- package/specs/add-redis-sqs-bedrock.md +128 -0
- package/specs/add-storage-dynamodb.md +106 -0
- package/specs/bedrock-model-catalog.md +131 -0
- package/specs/ci-pipeline.md +17 -0
- package/specs/cost-transparency.md +115 -0
- package/specs/custom-domains-and-ses.md +153 -0
- package/specs/database-suite-expansion.md +151 -0
- package/specs/db-connect.md +69 -0
- package/specs/db-lifecycle-migrations.md +159 -0
- package/specs/dependency-aware-init.md +176 -0
- package/specs/deploy-stack-to-grada-run-rebrand.md +45 -0
- package/specs/deployment-safety.md +170 -0
- package/specs/diagnose.md +16 -0
- package/specs/docs-hub.md +16 -0
- package/specs/dx-polish.md +46 -0
- package/specs/exec.md +25 -0
- package/specs/finops-cron-drift.md +161 -0
- package/specs/gc.md +26 -0
- package/specs/integration-suite.md +16 -0
- package/specs/logs.md +32 -0
- package/specs/rollback-live-polling.md +40 -0
- package/specs/secrets-pull-audit.md +51 -0
- package/specs/serverless-lambda-target.md +133 -0
- package/specs/status.md +31 -0
- package/specs/telemetry-and-spawn-hardening.md +69 -0
- package/specs/telemetry-hardening.md +35 -0
- package/src/commands/add.js +1111 -0
- package/src/commands/apply.js +214 -0
- package/src/commands/db/backup.js +229 -0
- package/src/commands/db/connect.js +304 -0
- package/src/commands/db/enable-vector.js +344 -0
- package/src/commands/db/import.js +604 -0
- package/src/commands/db/migrate.js +477 -0
- package/src/commands/db/restore.js +361 -0
- package/src/commands/db.js +87 -0
- package/src/commands/destroy.js +217 -0
- package/src/commands/diagnose.js +460 -0
- package/src/commands/doctor.js +109 -0
- package/src/commands/domain.js +685 -0
- package/src/commands/drift.js +243 -0
- package/src/commands/eject.js +127 -0
- package/src/commands/exec.js +222 -0
- package/src/commands/gc.js +250 -0
- package/src/commands/init.js +649 -0
- package/src/commands/logs.js +256 -0
- package/src/commands/rollback.js +323 -0
- package/src/commands/secrets.js +485 -0
- package/src/commands/sleep.js +347 -0
- package/src/commands/status.js +309 -0
- package/src/commands/sync-ai.js +115 -0
- package/src/commands/wake.js +337 -0
- package/src/core/parser.js +126 -0
- package/src/core/telemetry.js +244 -0
- package/src/data/bedrock-models.json +896 -0
- package/src/utils/addons.js +126 -0
- package/src/utils/ai-rules.js +59 -0
- package/src/utils/args.js +91 -0
- package/src/utils/aws.js +178 -0
- package/src/utils/backup.js +69 -0
- package/src/utils/bedrock-catalog.js +511 -0
- package/src/utils/capabilities.js +500 -0
- package/src/utils/command.js +65 -0
- package/src/utils/db-tunnel.js +164 -0
- package/src/utils/detector.js +298 -0
- package/src/utils/dockerCompose.js +65 -0
- package/src/utils/domains.js +73 -0
- package/src/utils/ecs-runner.js +289 -0
- package/src/utils/ecs.js +92 -0
- package/src/utils/frameworks.js +55 -0
- package/src/utils/generator.js +527 -0
- package/src/utils/hcl.js +426 -0
- package/src/utils/lambda-ecr.js +185 -0
- package/src/utils/prompts.js +278 -0
- package/src/utils/rds.js +131 -0
- package/src/utils/resolvers.js +174 -0
- package/src/utils/sleep-state.js +140 -0
- package/src/utils/sleep-targets.js +139 -0
- package/src/utils/system.js +42 -0
- package/src/utils/terraform.js +70 -0
- package/src/utils/visualizer.js +381 -0
- package/src/utils/warnings.js +49 -0
- package/templates/README.md +150 -0
- package/templates/docker/django.Dockerfile +40 -0
- package/templates/docker/go.Dockerfile +23 -0
- package/templates/docker/nestjs.Dockerfile +33 -0
- package/templates/docker/nextjs.Dockerfile +55 -0
- package/templates/docker/node.Dockerfile +24 -0
- package/templates/docker/nuxt.Dockerfile +47 -0
- package/templates/docker/python.Dockerfile +38 -0
- package/templates/docker/rails.Dockerfile +59 -0
- package/templates/docker/static.Dockerfile +32 -0
- package/templates/docker/svelte.Dockerfile +52 -0
- package/templates/github/deploy-lambda.yml +120 -0
- package/templates/github/deploy.yml +138 -0
- package/templates/github/drift.yml +112 -0
- package/templates/github/preview-lambda.yml +86 -0
- package/templates/github/preview.yml +69 -0
- package/templates/github/teardown.yml +43 -0
- package/templates/terraform/addons/bedrock.tf +34 -0
- package/templates/terraform/addons/cron-lambda.tf +78 -0
- package/templates/terraform/addons/cron.tf +101 -0
- package/templates/terraform/addons/dynamodb.tf +73 -0
- package/templates/terraform/addons/redis.tf +64 -0
- package/templates/terraform/addons/s3.tf +143 -0
- package/templates/terraform/addons/ses.tf +73 -0
- package/templates/terraform/addons/sqs.tf +67 -0
- package/templates/terraform/backend.tf +22 -0
- package/templates/terraform/cloudfront-lambda.tf +80 -0
- package/templates/terraform/cloudfront.tf +80 -0
- package/templates/terraform/database-aurora-postgresql.tf +92 -0
- package/templates/terraform/database-mysql.tf +72 -0
- package/templates/terraform/database.tf +71 -0
- package/templates/terraform/main-lambda.tf +229 -0
- package/templates/terraform/main.tf +296 -0
- package/templates/terraform/network.tf +95 -0
- package/templates/terraform/oidc.tf +64 -0
- package/templates/terraform/secrets.tf +31 -0
- package/templates/terraform/worker.tf +69 -0
- package/tests/__snapshots__/generator.test.js.snap +9633 -0
- package/tests/add.test.js +2037 -0
- package/tests/ai.test.js +94 -0
- package/tests/apply.test.js +488 -0
- package/tests/args.test.js +86 -0
- package/tests/aws.test.js +244 -0
- package/tests/capabilities.test.js +307 -0
- package/tests/cli.test.js +29 -0
- package/tests/command.test.js +100 -0
- package/tests/commands-import.test.js +74 -0
- package/tests/db.test.js +2704 -0
- package/tests/destroy.test.js +391 -0
- package/tests/detector.test.js +79 -0
- package/tests/diagnose.test.js +779 -0
- package/tests/doctor.test.js +202 -0
- package/tests/domain.test.js +899 -0
- package/tests/drift.test.js +243 -0
- package/tests/ecs.test.js +130 -0
- package/tests/eject.test.js +65 -0
- package/tests/exec.test.js +380 -0
- package/tests/gc.test.js +496 -0
- package/tests/generator.test.js +794 -0
- package/tests/headless.test.js +562 -0
- package/tests/lambda-ecr.test.js +185 -0
- package/tests/logs.test.js +447 -0
- package/tests/parser.test.js +160 -0
- package/tests/rds.test.js +244 -0
- package/tests/resolvers.test.js +282 -0
- package/tests/rollback.test.js +692 -0
- package/tests/secrets.test.js +752 -0
- package/tests/sleep-wake.test.js +1016 -0
- package/tests/status.test.js +370 -0
- package/tests/system.test.js +70 -0
- package/tests/telemetry.test.js +520 -0
- package/tests/terraform.test.js +84 -0
- package/tests/visualizer.test.js +496 -0
- package/vitest.config.js +9 -0
- package/index.js +0 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: logs
|
|
3
|
+
description: Stream CloudWatch logs for your ECS service.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Stream recent and live CloudWatch logs for the current project, without opening the AWS console.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- Resolves the log group (`/ecs/<project-name>`, overridable via `ECS_LOG_GROUP`) and region (`--region` → `AWS_REGION` → `terraform/main.tf` → `us-east-2`) automatically.
|
|
11
|
+
- Prints recent lines with dimmed ISO timestamps and task IDs; errors in red, warnings in yellow.
|
|
12
|
+
- With `-f`, polls every 2 seconds until Ctrl+C, which exits cleanly.
|
|
13
|
+
- On expired credentials, prints the `aws sso login` / `aws configure` hint and exits 1; on a missing log group, suggests the matching `aws logs describe-log-groups` lookup instead of throwing.
|
|
14
|
+
- On `--target lambda` projects, tails `/aws/lambda/<project-name>-fn` instead, and the service filter is ignored (Lambda stream names are request-based, not container names).
|
|
15
|
+
- Emits a `logs_streamed` telemetry event recording success and filter options.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx grada-run logs
|
|
21
|
+
npx grada-run logs api --tail 100 --error
|
|
22
|
+
npx grada-run logs -f --since 5m
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Flags
|
|
26
|
+
|
|
27
|
+
| Flag | Description |
|
|
28
|
+
| ---- | ----------- |
|
|
29
|
+
| `[service]` | Service/container filter. Defaults to the project service. |
|
|
30
|
+
| `--tail <n>` | Recent lines to show (default `50`). |
|
|
31
|
+
| `-f, --follow` | Stream live until interrupted. |
|
|
32
|
+
| `--error` | Show only error lines (`ERROR`, `FATAL`, `Exception`, `fail`, `5XX`). |
|
|
33
|
+
| `--since <duration>` | Look-back window, e.g. `5m`, `1h`, `1d` (default `1h` for one-shot reads). |
|
|
34
|
+
| `--region <region>` | Explicit AWS region override. |
|
|
35
|
+
|
|
36
|
+
## See also
|
|
37
|
+
|
|
38
|
+
- [exec](/grada/cli/exec/)
|
|
39
|
+
- [status](/grada/cli/status/)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: rollback
|
|
3
|
+
description: Roll back your ECS service to a previous task definition revision.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Two layers of deployment safety: your infrastructure rolls back bad deployments automatically, and you can manually return to any previous revision with one command.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- Your ECS service ships with a deployment circuit breaker — if a new deployment fails its health checks, AWS automatically rolls it back without you lifting a finger.
|
|
11
|
+
- `rollback` takes you back to a previous task definition revision on demand: pass a revision number, or pick from an interactive list showing each revision's container image and registration date.
|
|
12
|
+
- In automation and CI (or with `--headless`), it defaults to the most recent older revision with no prompt.
|
|
13
|
+
- Resolves its inputs automatically: cluster (`<project-name>-cluster`, overridable via `ECS_CLUSTER`), service (`<project-name>-service`, overridable via `ECS_SERVICE`), and region (`--region` → `AWS_REGION` → `terraform/main.tf` → `us-east-2`). `--workspace` targets a PR-preview environment's namespaced service.
|
|
14
|
+
- Watches the rollback deployment until it stabilizes (up to 5 minutes), and points you to `status` and `logs` if it fails or times out.
|
|
15
|
+
- ECS only: on `--target lambda` projects the command exits with the Lambda-native alternative — redeploy a previous image with `aws lambda update-function-code` (list SHA tags via `aws ecr describe-images`).
|
|
16
|
+
- Emits a `rollback_run` telemetry event recording success and outcome.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx grada-run rollback
|
|
22
|
+
npx grada-run rollback 12
|
|
23
|
+
npx grada-run rollback --skip-wait
|
|
24
|
+
npx grada-run rollback 12 --cluster myapp-cluster --service myapp-service
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Without a revision number, you'll see an interactive revision selector:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
? Select a task definition revision to roll back to:
|
|
31
|
+
Revision 13 — myapp:sha-9f2c1ab (2026-09-20)
|
|
32
|
+
Revision 12 — myapp:sha-77d0e4f (2026-09-18)
|
|
33
|
+
Revision 11 — myapp:sha-51b8c2d (2026-09-15)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Flags
|
|
37
|
+
|
|
38
|
+
| Flag | Description |
|
|
39
|
+
| ---- | ----------- |
|
|
40
|
+
| `[revision]` | Task revision to roll back to: a number (`12`), `family:revision` (`myapp-task:12`), or a full task definition ARN. Defaults to the most recent older revision (interactive prompt on a TTY). |
|
|
41
|
+
| `--cluster <name>` | Explicit cluster name override. |
|
|
42
|
+
| `--service <name>` | Explicit service name override. |
|
|
43
|
+
| `--region <region>` | Explicit AWS region override. |
|
|
44
|
+
| `--workspace <name>` | Roll back the PR-preview environment's service instead of production. |
|
|
45
|
+
| `--skip-wait` | Trigger the rollback and exit immediately without waiting for stabilization. |
|
|
46
|
+
|
|
47
|
+
## See also
|
|
48
|
+
|
|
49
|
+
- [status](/grada/cli/status/)
|
|
50
|
+
- [logs](/grada/cli/logs/)
|
|
51
|
+
- [diagnose](/grada/cli/diagnose/)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: secrets
|
|
3
|
+
description: Push, pull, and audit environment secrets synced with AWS Secrets Manager.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Sync your local `.env` file with the Secrets Manager vault provisioned for this project, so your deployed app reads the values at runtime without plaintext secrets ever touching the repo or CI/CD pipelines.
|
|
7
|
+
|
|
8
|
+
## secrets push
|
|
9
|
+
|
|
10
|
+
Uploads a local env file to the `<project-name>-secrets` vault via `UpdateSecretCommand`, then writes the pushed key names to `terraform/secret_keys.json` so Terraform and CI redeploy know which variables exist.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx grada-run secrets push
|
|
14
|
+
npx grada-run secrets push .env.production
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The optional positional argument is the path of the env file to push (resolved relative to the project root). It defaults to `.env` when omitted or blank.
|
|
18
|
+
|
|
19
|
+
**Smart follow-up based on what changed:**
|
|
20
|
+
|
|
21
|
+
- **Key names changed** (added/removed variables) — commit `terraform/secret_keys.json` and push to GitHub to trigger a deployment with the new variables. The ECS task definition is rebuilt from the updated key map.
|
|
22
|
+
- **Only values changed** (same key set) — the CLI offers a rolling ECS restart (`forceNewDeployment`) so running tasks pick up the new values immediately, no redeploy required.
|
|
23
|
+
- **Lambda target** — new values apply to fresh invocations automatically; no restart is offered or needed.
|
|
24
|
+
|
|
25
|
+
Region resolution is shared across all three commands (see Prerequisites), so they work even when no region is configured. Emits a `secrets_pushed` telemetry event. Exits non-zero on failure.
|
|
26
|
+
|
|
27
|
+
**Missing env file:** if the file does not exist, `push` does not throw. Interactively it asks `Would you like to create an empty <file> file now to get started?` — confirming creates the file (with parent directories) so you can fill it in and re-run; declining leaves everything untouched. With `--headless` or `CI=true` it prints a pointer to generate the file first and exits 1.
|
|
28
|
+
|
|
29
|
+
## secrets pull
|
|
30
|
+
|
|
31
|
+
Fetches the remote JSON payload from the `<project-name>-secrets` vault and merges it into your local env file — useful for onboarding a new machine or recovering after losing `.env`.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx grada-run secrets pull
|
|
35
|
+
npx grada-run secrets pull .env
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Merge behavior:**
|
|
39
|
+
|
|
40
|
+
- Remote keys are appended after your existing local keys; existing local order is preserved.
|
|
41
|
+
- Local-only variables are kept — pull never deletes them.
|
|
42
|
+
- If a key exists locally and remotely with different values, the CLI asks `Conflicting variables found. Overwrite local values with remote?` In `--headless` mode it overwrites automatically.
|
|
43
|
+
|
|
44
|
+
Values are written in standard `KEY="value"` format. Emits a `secrets_pull` telemetry event. Exits non-zero on failure (e.g. no remote vault yet — run `secrets push` first).
|
|
45
|
+
|
|
46
|
+
## secrets audit
|
|
47
|
+
|
|
48
|
+
Compares your local env file against the remote vault and prints a colored drift report — no files are modified.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx grada-run secrets audit
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `+ KEY (Missing locally)` in green — exists in AWS but not in your `.env`.
|
|
55
|
+
- `~ KEY (Mismatched value)` in yellow — exists in both with different values.
|
|
56
|
+
- `- KEY (Not tracked in AWS)` in dim — exists locally but was never pushed.
|
|
57
|
+
|
|
58
|
+
Ends with `Audit complete. N drifted variable(s) found.` Emits a `secrets_audit` telemetry event.
|
|
59
|
+
|
|
60
|
+
## Prerequisites
|
|
61
|
+
|
|
62
|
+
- Run `npx grada-run apply` first: the `<project-name>-secrets` vault is created during provisioning. If it does not exist yet, each command points you back to `apply`.
|
|
63
|
+
- Valid AWS credentials. On expired credentials, refresh with `aws sso login` or `aws configure`. See the [AWS credentials guide](/grada/guides/aws-credentials/).
|
|
64
|
+
- Region (all three commands): pass `--region <region>` explicitly, or rely on the automatic chain — `AWS_REGION` → `AWS_DEFAULT_REGION` → the `region` in `terraform/backend.tf` → default `us-east-2`.
|
|
65
|
+
|
|
66
|
+
## A note on `terraform/secret_keys.json`
|
|
67
|
+
|
|
68
|
+
This file contains **key names only** (e.g. `["API_KEY"]`), never values — it is safe to commit, and it **must** be committed: Terraform reads it during deployment to map each key into your ECS task definition.
|
|
69
|
+
|
|
70
|
+
## See also
|
|
71
|
+
|
|
72
|
+
- [Secrets management guide](/grada/guides/secrets-management/)
|
|
73
|
+
- [apply](/grada/cli/apply/)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: sleep & wake
|
|
3
|
+
description: Pause idle environments to save costs by scaling ECS services to zero and stopping RDS, then restore them with one command.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Pause a non-production or idle environment with a single command, and wake it back up when you need it — without opening the AWS Management Console.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- `sleep [env]` scales your ECS services (`app` and `worker`, when present) to `0` and stops the RDS instance or Aurora cluster, printing the estimated hourly/monthly compute savings.
|
|
11
|
+
- `wake [env]` starts the database first (waiting until it is `available`), then restores the exact ECS desired counts recorded at sleep time.
|
|
12
|
+
- `sleep` also pauses the `add cron` schedule (when configured) and suspends SQS worker auto-scaling, so no scheduled task or queued message wakes the environment back up; `wake` resumes both. Schedules that were never deployed and unregistered scaling targets are skipped gracefully.
|
|
13
|
+
- Sleeping the default (production) environment requires confirmation (`--yes` in automation); named environments sleep without prompting.
|
|
14
|
+
- AWS automatically restarts stopped RDS databases after 7 consecutive days — `sleep` prints the exact restart timestamp, and `wake` warns if the window already elapsed.
|
|
15
|
+
- Sleep state lives in `.grada/sleep-state.json` (one entry per environment, gitignored), so `wake` restores your original replica counts even for scaled-out services.
|
|
16
|
+
- On `--target lambda` projects, compute is already scale-to-zero, so `sleep`/`wake` manage only the database (and pause/resume the cron schedule) — no services are scaled or restored.
|
|
17
|
+
- Emits `sleep_run` / `wake_run` telemetry events recording the outcome.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx grada-run sleep staging
|
|
23
|
+
npx grada-run wake staging
|
|
24
|
+
npx grada-run sleep --yes
|
|
25
|
+
npx grada-run wake --no-wait
|
|
26
|
+
npx grada-run sleep staging --skip-db
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Flags
|
|
30
|
+
|
|
31
|
+
| Flag | Description |
|
|
32
|
+
| ---- | ----------- |
|
|
33
|
+
| `[env]` | Positional environment name (e.g. `staging`, `pr-42`). Aliases `--workspace`. Defaults to the default environment. |
|
|
34
|
+
| `--workspace <name>` | Explicit environment name. Wins over the positional `[env]`. |
|
|
35
|
+
| `--project-name <name>` | Explicit project name override (defaults to the name in `terraform/main.tf`, then the directory name). |
|
|
36
|
+
| `--cluster <name>` | Explicit ECS cluster override. |
|
|
37
|
+
| `--service <name>` | Explicit ECS app service override. |
|
|
38
|
+
| `--db-identifier <id>` | Explicit database identifier override. |
|
|
39
|
+
| `--region <region>` | Explicit AWS region override. |
|
|
40
|
+
| `--skip-db` | Scale ECS services only; leave the database running. |
|
|
41
|
+
| `--no-wait` | On `wake`, return immediately instead of waiting for RDS `available` and ECS tasks to reach their desired counts. |
|
|
42
|
+
| `--yes` | Skip the production confirmation prompt on `sleep` (also accepts `--force`; required in `--headless`/CI runs, which fail instead of prompting). |
|
|
43
|
+
|
|
44
|
+
Both commands are idempotent: re-sleeping an asleep environment (or waking an awake one) reports the current state instead of failing.
|
|
45
|
+
|
|
46
|
+
## Cost & billing drivers
|
|
47
|
+
|
|
48
|
+
While asleep you stop paying for Fargate task hours (`~$9.01/mo` per 256/512 replica) and RDS instance compute (`~$11.68/mo` for `db.t4g.micro`). 20 GB gp3 storage (`~$2.30/mo`), the ALB (`~$22.27/mo`), ElastiCache Valkey (`~$9.49/mo` — it has no pause API), and Secrets Manager secrets keep billing until you run `destroy`. Aurora Serverless v2 already idles at 0 ACU, so stopping it only prevents active wake-ups. Lambda projects skip the ALB line entirely — asleep, only storage, secrets, and (if present) Valkey keep billing.
|
|
49
|
+
|
|
50
|
+
## See also
|
|
51
|
+
|
|
52
|
+
- [status](/grada/cli/status/)
|
|
53
|
+
- [destroy](/grada/cli/destroy/)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: status
|
|
3
|
+
description: Check ECS service health and CloudWatch alarms.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Instant health dashboard for your deployment. Exits cleanly when healthy; hands off to `diagnose` automatically when degraded.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- Queries ECS (`desiredCount` vs `runningCount`/`pendingCount`) and project-prefixed CloudWatch alarms.
|
|
11
|
+
- Prints a color-coded dashboard: service status, replicas (green/yellow/red), and alarm states.
|
|
12
|
+
- If degraded (`runningCount < desiredCount` or any alarm firing), prints the degraded notice, invokes `diagnose`, and exits 1.
|
|
13
|
+
- Resolves region like `logs` (`--region` → `AWS_REGION` → `terraform/main.tf` → `us-east-2`); cluster, service, and log group default to `<project-name>-cluster`, `<project-name>-service`, `/ecs/<project-name>` (overridable via `ECS_CLUSTER` / `ECS_SERVICE` / `ECS_LOG_GROUP`).
|
|
14
|
+
- On `--target lambda` projects, reads function state via the AWS CLI (which must be installed) instead of ECS, printing function state, last update status, memory/timeout, and deployed image.
|
|
15
|
+
- Emits a `status_run` telemetry event recording health and outcome.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx grada-run status
|
|
21
|
+
npx grada-run status --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Flags
|
|
25
|
+
|
|
26
|
+
| Flag | Description |
|
|
27
|
+
| ---- | ----------- |
|
|
28
|
+
| `--json` | Output the raw status payload as JSON; disables auto-diagnose. |
|
|
29
|
+
| `--region <region>` | Explicit AWS region override. |
|
|
30
|
+
|
|
31
|
+
## See also
|
|
32
|
+
|
|
33
|
+
- [exec](/grada/cli/exec/)
|
|
34
|
+
- [diagnose](/grada/cli/diagnose/)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: sync-ai
|
|
3
|
+
description: Regenerate AI assistant rules for an existing project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Give your AI coding assistants up-to-date grada context after project settings change, so they generate correct Terraform and deployment instructions instead of hallucinating them.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- Prompts you to choose which AI assistants to configure, then writes the matching rule files with your project's region (from `region` in `terraform/main.tf`) and container port (from `containerPort` in `terraform/main.tf`).
|
|
11
|
+
- Writes a full rule file for Cursor (`.cursor/rules/grada.mdc`), Roo (`.roo/rules/grada.md`), Trae (`.trae/rules/project_rules.md`), and Continue (`.prompts/grada.prompt`); injects a managed block into the existing config for Windsurf (`.windsurfrules`), Copilot (`.github/copilot-instructions.md`), Claude (`CLAUDE.md`), Goose (`.goosehints`), and Aider (`.aider.conf.yml`).
|
|
12
|
+
- Exits without writing anything when no assistants are selected.
|
|
13
|
+
- Emits a `sync_ai_executed` telemetry event listing the selected assistants.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx grada-run sync-ai
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Flags
|
|
22
|
+
|
|
23
|
+
This command accepts no CLI flags. Assistant selection is interactive.
|
|
24
|
+
|
|
25
|
+
## See also
|
|
26
|
+
|
|
27
|
+
- [npx grada-run](/grada/cli/init/)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Stack Architecture
|
|
3
|
+
description: How the generated VPC, load balancer, cluster, CDN, data stores, and CI pipeline fit together.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every grada project generates the same shape: a public-subnet VPC, an ALB-fronted Fargate cluster (or a scale-to-zero Lambda function with `--target lambda`), CloudFront at the edge, and a keyless CI pipeline that ships images while Terraform owns the infrastructure. This page is the map; each piece links to its reference.
|
|
7
|
+
|
|
8
|
+
## Request path
|
|
9
|
+
|
|
10
|
+
Internet → **CloudFront** → **ALB** → **ECS tasks**. The distribution's origin is the load balancer (`cloudfront.tf`), so web traffic enters through the CDN with SSL terminated at the edge; the `Direct URL` printed by `apply` bypasses it for debugging.
|
|
11
|
+
|
|
12
|
+
Tasks run with `awsvpc` networking in **public subnets** spread across availability zones (`10.0.0.0/16` VPC, one subnet per AZ, internet gateway attached). There is intentionally **no NAT gateway** — tasks get public IPs and talk out directly, which saves ~$33/mo versus a conventional private-subnet layout. Isolation comes from security groups: the ALB accepts public internet traffic, tasks accept traffic only from the ALB, and outbound access stays open for image pulls and external APIs.
|
|
13
|
+
|
|
14
|
+
## Compute and images
|
|
15
|
+
|
|
16
|
+
One ECS cluster holds the `app` service, plus an optional private `worker` service with no load balancer (see [Background Workers](/grada/guides/background-workers/)). Both run the same ECR image: the pipeline builds once per push and tags it with the commit SHA (the immutable deploy artifact) and `latest`. Scheduled jobs ([`add cron`](/grada/cli/add/)) reuse that same image — an EventBridge Scheduler rule launches a one-off Fargate task inside the VPC on your `cron(...)` or `rate(...)` expression, so there is no always-on worker to pay for.
|
|
17
|
+
|
|
18
|
+
Two IAM roles split concerns: the **execution role** pulls images and reads secrets at boot, while the **task role** carries workload permissions — every [`add`](/grada/cli/add/) addon attaches its least-privilege policy here, so application code uses the AWS SDK with no keys.
|
|
19
|
+
|
|
20
|
+
Deploys never rebuild infrastructure: the pipeline registers a new task-definition revision per push and updates the service to it, while Terraform ignores the service's `task_definition` so the next `apply` never reverts a code deploy. An ECS deployment circuit breaker rolls back failed rollouts automatically, and every revision stays registered so [`rollback`](/grada/cli/rollback/) always has history. See [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/).
|
|
21
|
+
|
|
22
|
+
## Serverless target (`--target lambda`)
|
|
23
|
+
|
|
24
|
+
Passing `--target lambda` to [`init`](/grada/cli/init/) generates an alternate scale-to-zero topology with the same VPC, ECR repository, IAM roles, secrets vault, and CloudFront distribution — only the compute layer changes:
|
|
25
|
+
|
|
26
|
+
Internet → **CloudFront** → **API Gateway HTTP API v2** → **Lambda function**. The generated `Dockerfile` embeds the AWS Lambda Web Adapter extension, so standard HTTP servers (`app.listen(process.env.PORT)`) serve API Gateway events with zero application code changes. The fixed compute and load-balancer baseline is **$0.00/mo** (Lambda and HTTP APIs bill per request); a no-database project totals ~$0.80/mo in Secrets Manager.
|
|
27
|
+
|
|
28
|
+
Deploys push the SHA-tagged image to ECR and call `update-function-code`, which Terraform ignores (mirroring the ECS `task_definition` rule) so code deploys and `apply` never fight. On day 0, `apply` seeds a minimal placeholder image into ECR automatically — Lambda's API rejects empty repositories — so the first provision succeeds before any code push.
|
|
29
|
+
|
|
30
|
+
Projects with a database attach the function to the VPC subnets (still no NAT gateway) and receive credentials as `DB_*` environment variables, since VPC-attached functions cannot reach Secrets Manager without a paid VPC endpoint. Non-database functions stay outside the VPC with direct internet access; `add db:redis` attaches the VPC config on demand. Cron schedules invoke the function directly with a JSON payload carrying the configured command — handle scheduled events in application code.
|
|
31
|
+
|
|
32
|
+
Day-2 commands adapt: `status` and `diagnose` read function configuration via the AWS CLI, `logs` tails `/aws/lambda/<project>-fn`, and `sleep`/`wake` manage only the database (compute needs no scaling). `exec` and `rollback` are ECS-only and exit with the Lambda-native alternative.
|
|
33
|
+
|
|
34
|
+
### Fargate vs Lambda tradeoffs
|
|
35
|
+
|
|
36
|
+
Both targets share the VPC, ECR, IAM, secrets, and CloudFront layers — pick by traffic shape, not by feature set:
|
|
37
|
+
|
|
38
|
+
- **Cost crossover.** Lambda idles at $0 and bills per request (API Gateway HTTP API at $1.00 per million requests, plus Lambda request and GB-second compute charges), so sporadic or bursty workloads cost pennies. Under sustained high-concurrency traffic those per-request charges catch up to and pass Fargate's flat ~$31/mo compute+ALB baseline, and always-on containers become the more cost-effective steady state. See [Understanding Your AWS Bill](/grada/guides/understanding-your-bill/).
|
|
39
|
+
- **Database connections.** Fargate runs a fixed handful of tasks with persistent, pooled connections. Lambda can burst toward 1,000 concurrent executions, and the generated stack connects each execution straight to RDS with no proxy in between — enough simultaneous cold starts will exhaust a `db.t4g.micro` connection limit and fail queries until executions drain. For high-concurrency Lambda workloads against a relational database, keep client pools tiny with aggressive idle timeouts, or place RDS Proxy in front of the database yourself.
|
|
40
|
+
- **Cold starts.** Fargate tasks are always warm behind the ALB. VPC-attached Lambda container images (any project with a database or Redis) pay multi-second cold starts on scale-out — fine for background-tolerant traffic, noticeable on latency-sensitive paths.
|
|
41
|
+
- **Request limits.** API Gateway caps every Lambda invocation behind it at 30 seconds and 10 MB of payload, and a single function execution can never exceed 15 minutes — long responses, in-request file processing, SSE streams, and WebSockets don't fit. The ALB imposes no such ceilings, so ECS carries long-lived and streaming traffic.
|
|
42
|
+
- **Background workers and queues.** ECS keeps a first-class worker story: Procfile workers become a dedicated service, and `queue:sqs` drives a scale-to-zero worker with queue-depth autoscaling. Lambda runs one function — Procfile workers are skipped at scaffold time, SQS queues ship without a consumer (poll from function code or wire an event source mapping yourself), and cron schedules arrive as JSON-payload invokes your code must handle.
|
|
43
|
+
- **Outbound network.** ECS tasks carry public IPs and reach the open internet directly. Lambda functions attached to the VPC (any project with a database or Redis) get private-only network interfaces, and the generated VPC has no NAT gateway — so they cannot call third-party APIs unless you add NAT or VPC endpoints yourself. Non-VPC functions keep direct internet access.
|
|
44
|
+
|
|
45
|
+
| | ECS Fargate + ALB | Lambda + API Gateway v2 |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Idle cost | ~$31/mo flat | $0 |
|
|
48
|
+
| Cost at sustained scale | flat per task (cheaper steady state) | per request + compute (grows with traffic) |
|
|
49
|
+
| Cold starts | none (always warm) | multi-second on VPC scale-out |
|
|
50
|
+
| Max request duration | no hard cap (ALB) | 30s API Gateway cap, 15-min function max |
|
|
51
|
+
| DB connections | fixed pooled tasks | per-execution, no proxy |
|
|
52
|
+
| Background workers | dedicated service + SQS autoscaling | none (queues ship unconsumed) |
|
|
53
|
+
| Outbound internet | yes (public IPs) | only when outside the VPC |
|
|
54
|
+
| WebSockets / streaming | yes, via ALB | no |
|
|
55
|
+
| Day-2 ops | `exec`, `rollback`, migration gate | adapted `status`/`logs`/`diagnose`; no `exec`/`rollback` |
|
|
56
|
+
| Web scaling | fixed desired count | automatic to 1,000 concurrent |
|
|
57
|
+
|
|
58
|
+
Choose **ECS Fargate** when traffic is steady or latency-sensitive (product APIs, SaaS backends), responses can exceed 30 seconds or stream, background workers or queue consumers are part of the design, or handlers need persistent database connections and outbound internet side by side.
|
|
59
|
+
|
|
60
|
+
Choose **Lambda** when traffic is sporadic, bursty, or unpredictable (side projects, internal tools, webhooks), $0 idle cost matters more than warm latency, and the workload is request-scoped with no workers or long-lived connections — ideally with Aurora Serverless (which scales with the function) or no database at all.
|
|
61
|
+
|
|
62
|
+
## Data and secrets
|
|
63
|
+
|
|
64
|
+
- **Database** (when enabled) runs on RDS in **isolated subnets** with its own subnet group — no route to the internet. Pick the engine at scaffold time (`postgres`, `mysql`, or scale-to-zero `aurora-postgresql` via `--db-engine`). Reach it from your laptop via [`db connect`](/grada/cli/db/), and run migrations inside the VPC with [`db migrate`](/grada/cli/db/).
|
|
65
|
+
- **Secrets** live in Secrets Manager as one app secret, injected as environment variables at container boot from the key map in `terraform/secret_keys.json`. See [Secrets Management](/grada/guides/secrets-management/).
|
|
66
|
+
- **State** lives in an encrypted S3 bucket using native S3 locking (`use_lockfile`), so concurrent applies are safe without a lock table.
|
|
67
|
+
|
|
68
|
+
## CDN, domain, and email
|
|
69
|
+
|
|
70
|
+
CloudFront serves the app globally from the ALB origin. [`domain add`](/grada/cli/domain/) attaches your own hostname with an automated `us-east-1` ACM certificate; [`add email:ses`](/grada/cli/add/) provisions SES sending on the same domain with DKIM/SPF/DMARC. Both are optional day-2 steps over the base stack.
|
|
71
|
+
|
|
72
|
+
## Observability
|
|
73
|
+
|
|
74
|
+
One CloudWatch log group per project (`/ecs/<project>`, 14-day retention) collects web and worker streams; an alarm fires when the ALB serves more than ten 5XX errors in two minutes. [`status`](/grada/cli/status/) renders the health dashboard, [`diagnose`](/grada/cli/diagnose/) explains crashed tasks, and [`logs`](/grada/cli/logs/) streams without the console.
|
|
75
|
+
|
|
76
|
+
## Operations
|
|
77
|
+
|
|
78
|
+
Idle environments cost nothing in compute: [`sleep` / `wake`](/grada/cli/sleep/) scales ECS services to zero and stops RDS — printing the exact hourly/monthly savings and the 7-day AWS auto-restart timestamp — then restores the exact replica counts on wake. Console click-ops never go unnoticed: the opt-in `drift.yml` workflow runs `terraform plan` daily and opens a GitHub Issue on drift, and [`drift`](/grada/cli/drift/) runs the same check locally.
|
|
79
|
+
|
|
80
|
+
## Preview workspaces
|
|
81
|
+
|
|
82
|
+
Each open pull request gets a Terraform workspace (`preview.yml`) running the same files renamed by `app_name` plus an environment suffix — a full copy of the stack that `teardown.yml` destroys on close. A few resources are deliberately shared instead of copied (the ECR repository, Secrets Manager lookups), and account-wide singletons — the custom-domain ACM certificate and aliases, the SES domain identity/DKIM/DNS — are scoped to the production (`default`) workspace via `count` guards, so previews neither duplicate them nor delete them on teardown; previews serve over their own `*.cloudfront.net` URL and inherit SES sending permission. See [Ephemeral PR Previews](/grada/guides/ephemeral-pr-previews/).
|
|
83
|
+
|
|
84
|
+
## See also
|
|
85
|
+
|
|
86
|
+
- [Quickstart (5 minutes)](/grada/guides/quickstart/) for the fastest path through this stack.
|
|
87
|
+
- [Understanding Your AWS Bill](/grada/guides/understanding-your-bill/) for what each piece costs.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Troubleshooting AWS Credentials & Authentication
|
|
3
|
+
description: Troubleshooting AWS authentication, expired tokens, and SSO logins.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 9
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`grada` interacts directly with AWS APIs (Secrets Manager, ECS, CloudWatch, S3) using the official AWS SDK v3 default credential provider chain.
|
|
9
|
+
|
|
10
|
+
When you encounter an `UnrecognizedClientException` or `ExpiredTokenException`, your local AWS authentication state has lapsed. Every command reports this identically: it stops its spinner, suggests `aws sso login` or `aws configure`, links back to this guide, and exits 1.
|
|
11
|
+
|
|
12
|
+
If the message instead says the AWS CLI was not found, install it first ([install guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)), then refresh your credentials as below.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Quick Refresh by Setup Type
|
|
17
|
+
|
|
18
|
+
### A. AWS IAM Identity Center (AWS SSO)
|
|
19
|
+
If your organization or personal account uses IAM Identity Center / SSO:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Log in to refresh your active session token
|
|
23
|
+
aws sso login
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If you use named profiles:
|
|
27
|
+
```bash
|
|
28
|
+
aws sso login --profile your-profile-name
|
|
29
|
+
export AWS_PROFILE=your-profile-name
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### B. Standard Long-Lived Access Keys (`~/.aws/credentials`)
|
|
35
|
+
If you use long-lived `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` pairs:
|
|
36
|
+
|
|
37
|
+
1. Verify credentials configured:
|
|
38
|
+
```bash
|
|
39
|
+
aws sts get-caller-identity
|
|
40
|
+
```
|
|
41
|
+
2. If invalid or missing:
|
|
42
|
+
```bash
|
|
43
|
+
aws configure
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### C. Temporary Session Tokens (`AWS_SESSION_TOKEN`)
|
|
49
|
+
If you assumed an IAM role or exported manual session tokens in your terminal:
|
|
50
|
+
|
|
51
|
+
Check if stale environment variables are overriding your global credentials:
|
|
52
|
+
```bash
|
|
53
|
+
echo $AWS_SESSION_TOKEN
|
|
54
|
+
```
|
|
55
|
+
If expired, clear them:
|
|
56
|
+
```bash
|
|
57
|
+
unset AWS_ACCESS_KEY_ID
|
|
58
|
+
unset AWS_SECRET_ACCESS_KEY
|
|
59
|
+
unset AWS_SESSION_TOKEN
|
|
60
|
+
```
|
|
61
|
+
Then re-authenticate via `aws configure` or `aws sso login`.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. Common Error References
|
|
66
|
+
|
|
67
|
+
| Error Name | Root Cause | Solution |
|
|
68
|
+
| :--- | :--- | :--- |
|
|
69
|
+
| `UnrecognizedClientException` | The security token is unrecognized, mistyped, or expired. | Run `aws sso login` or re-run `aws configure`. |
|
|
70
|
+
| `ExpiredTokenException` | Temporary STS credentials passed their validity window (typically 1–12 hrs). | Refresh STS credentials or log into SSO again. |
|
|
71
|
+
| `AccessDeniedException` | User or role lacks IAM permissions for ECS, Secrets Manager, or S3. | Ensure your IAM user has adequate deployment permissions. |
|
|
72
|
+
| `ResourceNotFoundException` | Target cluster, secret, or log group does not exist in target region. | Verify `AWS_REGION` and ensure infrastructure was provisioned via `grada apply`. |
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Background Workers
|
|
3
|
+
description: Run background jobs on a private ECS worker service — how it is created, SQS scale-to-zero, and day-2 operations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Long-running jobs (Celery, Sidekiq, BullMQ workers, queue pollers) run on a second ECS Fargate service that shares your web container's image, secrets, and database wiring but takes no HTTP traffic. (ECS targets only — `--target lambda` projects run a single function with no worker service; Procfile workers are skipped at scaffold time.)
|
|
7
|
+
|
|
8
|
+
## What the worker service is
|
|
9
|
+
|
|
10
|
+
`terraform/worker.tf` defines a private `aws_ecs_service.worker`: same ECR image and cluster as the web service, same Secrets Manager payload and database variables, and its own task definition whose container runs your worker command instead of the web server. There is deliberately **no load balancer block**, so nothing routes internet traffic to it. Logs go to the shared `/ecs/<project>` group with the `worker` stream prefix, keeping them separable from web logs.
|
|
11
|
+
|
|
12
|
+
New services start with `desired_count = 1`, but the service ignores `desired_count` changes in Terraform so queue-depth auto-scaling can manage the count without apply-time drift.
|
|
13
|
+
|
|
14
|
+
## How you get one
|
|
15
|
+
|
|
16
|
+
The worker service is created at init time, from either source:
|
|
17
|
+
|
|
18
|
+
- A `worker:` entry in your `Procfile` — see [Heroku (Procfile)](/grada/migrations/heroku-procfile-to-aws/).
|
|
19
|
+
- The scaffold worker prompt, pre-filled from what detection finds (Procfile entry, worker dependencies, or Compose commands) — see [`npx grada-run`](/grada/cli/init/).
|
|
20
|
+
|
|
21
|
+
Either path writes the command into `worker.tf` (`WORKER_COMMAND`) and manages the file like any other generated file.
|
|
22
|
+
|
|
23
|
+
## SQS scale-to-zero
|
|
24
|
+
|
|
25
|
+
`add queue:sqs` extends the worker with Application Auto Scaling driven by `ApproximateNumberOfMessagesVisible`:
|
|
26
|
+
|
|
27
|
+
- **Scale out:** one task per minute while the queue is non-empty, up to 5 tasks.
|
|
28
|
+
- **Scale in:** back to 0 after the queue stays empty for five minutes — a parked worker costs nothing in compute.
|
|
29
|
+
|
|
30
|
+
The scaling target, both step-scaling policies, and both CloudWatch alarms live in `sqs.tf`, and AWS creates the required service-linked role automatically on first registration. Addon environment variables are injected into the worker container as well as the web container.
|
|
31
|
+
|
|
32
|
+
## Adding a worker later
|
|
33
|
+
|
|
34
|
+
There is no `add worker` command: if you scaffolded without a worker, `add queue:sqs` still creates the queue and injects its URLs, but renders the auto-scaling block **commented out**. To activate it later, add `terraform/worker.tf` — re-run init (backup and regenerate, then restore hand-edited and addon files from the `.bak` copy; see [Re-running Init Safely](/grada/guides/rerun-init/)) or copy `worker.tf` from an equivalent fresh scaffold and set the command — uncomment the block in `sqs.tf`, and `apply`.
|
|
35
|
+
|
|
36
|
+
## Day-2 operations and cost
|
|
37
|
+
|
|
38
|
+
- Stream worker output with [`logs`](/grada/cli/logs/) — worker entries carry the `worker` stream prefix in the shared group — and open a shell with [`exec`](/grada/cli/exec/) using its service and container overrides.
|
|
39
|
+
- A running worker roughly doubles the Fargate baseline (~$18.02/mo at micro size), falling to $0 compute while its queue is empty; each open PR preview runs its own copy while the PR is open. See [Understanding Your AWS Bill](/grada/guides/understanding-your-bill/).
|
|
40
|
+
|
|
41
|
+
## See also
|
|
42
|
+
|
|
43
|
+
- [Heroku (Procfile)](/grada/migrations/heroku-procfile-to-aws/) for Procfile process mapping.
|
|
44
|
+
- [add](/grada/cli/add/) for `queue:sqs` flags and cost drivers — or `add cron` for scheduled one-off tasks that need no always-on worker.
|
|
45
|
+
- [Re-running Init Safely](/grada/guides/rerun-init/) for regeneration behavior.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: CI/CD Pipeline & First Deploy
|
|
3
|
+
description: How the generated GitHub Actions workflow builds, scans, and deploys your app with zero stored AWS keys.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Every `npx grada-run` run generates `.github/workflows/deploy.yml`. This page explains what that pipeline does, when it runs, and why your site returns `503` until the first push completes.
|
|
9
|
+
|
|
10
|
+
## When it runs
|
|
11
|
+
|
|
12
|
+
The workflow triggers on two events (`templates/github/deploy.yml`):
|
|
13
|
+
|
|
14
|
+
- A `push` to your deploy branch (`{{DEPLOY_BRANCH}}`, chosen during setup).
|
|
15
|
+
- A weekly Sunday cron (`0 0 * * 0`) that re-applies the Terraform configuration, so drift and base-image updates converge automatically.
|
|
16
|
+
|
|
17
|
+
The region, ECR repository, ECS cluster, and ECS service names are baked in at generation time as `<project>-repo`, `<project>-cluster`, and `<project>-service`.
|
|
18
|
+
|
|
19
|
+
## No stored AWS keys
|
|
20
|
+
|
|
21
|
+
Authentication uses GitHub OIDC, not long-lived credentials. The workflow declares:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
permissions:
|
|
25
|
+
id-token: write
|
|
26
|
+
contents: read
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
and assumes the `{{PROJECT_NAME}}-github-actions-role` IAM role created by `terraform/oidc.tf`. There is nothing to rotate and no secret to leak. (If your AWS account already has a GitHub OIDC provider, set `create_oidc_provider = false` in `terraform/oidc.tf` — see [apply](/grada/cli/apply/).)
|
|
30
|
+
|
|
31
|
+
## The five stages
|
|
32
|
+
|
|
33
|
+
1. **IaC security scan.** Trivy scans `terraform/` for vulnerabilities, secrets, and misconfigurations (`CRITICAL,HIGH`). It is informational only (`exit-code: '0'`), so it never blocks the build; results land in the GitHub step summary.
|
|
34
|
+
2. **Infrastructure sync.** The `grada-run/grada-action@v1` step runs Terraform against `terraform/`, so infrastructure changes committed alongside code are applied before the new image rolls out.
|
|
35
|
+
3. **Build & push.** The workflow logs in to Amazon ECR, runs `docker build` on your generated `Dockerfile`, and tags the result with both the short commit SHA (e.g. `abc1234`, the immutable deploy artifact) and `latest` (kept for convenience and scanning).
|
|
36
|
+
4. **Container scan.** Trivy scans the built image (`os,library`, `ignore-unfixed: true`), again informational only with results in the step summary.
|
|
37
|
+
5. **Deploy.** Both tags are pushed to ECR then the workflow registers a brand-new ECS task definition revision pinned to the SHA-tagged image and deploys it (`aws ecs update-service --task-definition <new-revision> --force-new-deployment`), which rolls the new image across your tasks behind the ALB. Because every push creates a fresh revision, `npx grada-run rollback [revision]` always has history to return to — and Terraform is configured to leave the service's task definition alone (`lifecycle { ignore_changes = [task_definition] }`), so the next `apply` never reverts a code-only deploy.
|
|
38
|
+
|
|
39
|
+
## Lambda target pipeline
|
|
40
|
+
|
|
41
|
+
On `--target lambda` projects the same `deploy.yml` shape applies, but the Deploy stage pushes the SHA-tagged image to ECR and calls `aws lambda update-function-code` (then `aws lambda wait function-updated`) instead of registering a task definition — Terraform ignores the function's `image_uri` (mirroring the ECS `task_definition` rule) so code deploys and `apply` never fight. There is no task-revision history, so `rollback` is ECS-only; redeploy a previous SHA tag to revert.
|
|
42
|
+
|
|
43
|
+
## Optional pre-deploy migration gate
|
|
44
|
+
|
|
45
|
+
`db migrate --cmd "<command>" --setup-ci` adds a migration step to the Deploy stage: after the new task definition is registered and before the service updates, it runs your migration command as a one-off ECS task against the newly built image — a failing migration halts the release automatically. Re-running the command updates the wired step in place. `init` can wire the same gate at scaffold time with `--setup-ci-migrate` (or the interactive prompt when a database and migration command are detected). ECS targets only — Lambda projects skip the gate (run migrations from CI against your database endpoint instead). See [`db migrate`](/grada/cli/db/).
|
|
46
|
+
|
|
47
|
+
## Scheduled drift detection (opt-in)
|
|
48
|
+
|
|
49
|
+
`--setup-ci-drift` (or `drift --setup` on an existing project) scaffolds a second workflow, `.github/workflows/drift.yml`, that runs `terraform plan` daily at 06:00 UTC plus on manual dispatch. When live AWS state differs from Terraform it opens (or updates, without spamming) a GitHub Issue labeled `iac-drift` with the plan diff; when drift resolves it comments `✅ Drift resolved` and closes the issue. Set a `SLACK_WEBHOOK_URL` repository secret to also post alerts to Slack. Run `npx grada-run drift` anytime for the same check locally. See [`drift`](/grada/cli/drift/).
|
|
50
|
+
|
|
51
|
+
## Why you see a 503 first
|
|
52
|
+
|
|
53
|
+
`npx grada-run apply` provisions the ALB, cluster, and service, but no container image exists until this workflow runs once. Pushing to your deploy branch (`git add . && git commit -m "ci: infra" && git push`) builds and deploys the first image, clearing the `503`. If the service stays unhealthy after that, run `npx grada-run diagnose` — usually the container failed its ALB health check (see [Dockerfiles](/grada/guides/dockerfiles/)). (On `--target lambda` projects the same flow provisions the API Gateway and function instead; `apply` seeds a placeholder image so Day-0 succeeds, and the first push replaces it.)
|
|
54
|
+
|
|
55
|
+
## Related workflows
|
|
56
|
+
|
|
57
|
+
- `preview.yml` / `teardown.yml` exist only when ephemeral PR previews are enabled. See [Ephemeral PR Previews](/grada/guides/ephemeral-pr-previews/).
|
|
58
|
+
- Secrets are injected at deploy time from AWS Secrets Manager, never from the repo. See [Secrets Management](/grada/guides/secrets-management/).
|
|
59
|
+
|
|
60
|
+
## See also
|
|
61
|
+
|
|
62
|
+
- [Quickstart](/grada/guides/quickstart/) for the 5-minute path that ends here.
|
|
63
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for what the pipeline builds.
|
|
64
|
+
- Migrating? See [Vercel (Next.js)](/grada/migrations/nextjs-vercel-to-aws/), [Vercel (Astro)](/grada/migrations/astro-vercel-to-aws/), [Vercel (SvelteKit)](/grada/migrations/sveltekit-vercel-to-aws/), and [Heroku (Procfile)](/grada/migrations/heroku-procfile-to-aws/).
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Managed Database Connections"
|
|
3
|
+
description: "Provision a managed AWS RDS PostgreSQL database for backend frameworks."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 6
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
When you run `npx grada-run` for a backend framework (Node, Django, Rails, Go, etc.), the CLI prompts you to automatically provision a managed AWS RDS PostgreSQL database. The database adds a fixed monthly cost on top of the stack baseline — the `apply` preview itemizes it before you provision.
|
|
9
|
+
|
|
10
|
+
## Zero-Trust Architecture
|
|
11
|
+
|
|
12
|
+
If you select "Yes", `grada` builds a true zero-trust network topology:
|
|
13
|
+
1. The PostgreSQL instance is deployed into heavily restricted **Isolated Subnets**.
|
|
14
|
+
2. It is given a strict Security Group that *only* allows inbound traffic from your specific ECS Fargate containers on port `5432`.
|
|
15
|
+
3. The database is completely inaccessible from the public internet.
|
|
16
|
+
|
|
17
|
+
## Auto-Injected Environment Variables
|
|
18
|
+
|
|
19
|
+
You do not need to configure database connection strings manually. The generated Terraform automatically creates a secure, random master password in AWS Secrets Manager and injects the following environment variables directly into your running containers:
|
|
20
|
+
|
|
21
|
+
* `DB_HOST` (The internal AWS DNS endpoint)
|
|
22
|
+
* `DB_PORT` (5432, or 3306 for MySQL)
|
|
23
|
+
* `DB_NAME` (Your deterministic database name, derived from your project name)
|
|
24
|
+
* `DB_USER` (Injected securely at runtime)
|
|
25
|
+
* `DB_PASSWORD` (Injected securely at runtime)
|
|
26
|
+
|
|
27
|
+
To connect your application, simply configure your ORM (Prisma, Django, TypeORM, Active Record) to read from these grada injected variables.
|
|
28
|
+
|
|
29
|
+
Most frameworks expect a single connection string (e.g., `DATABASE_URL`). Construct it from the injected variables at runtime:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If the password contains special characters (e.g., `@`, `[`, `/`), percent-encode it before placing it in the URI.
|
|
36
|
+
|
|
37
|
+
RDS enforces TLS (`rds.force_ssl = 1`): libpq-based clients negotiate it automatically, but drivers that default to plaintext need an explicit opt-in — append `?sslmode=require` to the URL (Prisma, JDBC-style clients) or pass the driver's SSL option (e.g. `ssl` in Node `pg`).
|
|
38
|
+
|
|
39
|
+
## Running Database Migrations
|
|
40
|
+
|
|
41
|
+
Because the database is in an isolated subnet, you cannot run schema migrations directly from your local laptop.
|
|
42
|
+
The best practice is [`db migrate`](/grada/cli/db/) — it launches a short-lived ECS task inside your VPC that runs your migration command (auto-detected for Prisma, Drizzle, Alembic, Django, Rails, and `db:migrate` npm scripts, or pass `--cmd`), streams the logs to your terminal, and exits with your migration's exit code.
|
|
43
|
+
|
|
44
|
+
To gate releases on migrations, run `db migrate --cmd "<command>" --setup-ci` once: it adds a pre-deploy step to `.github/workflows/deploy.yml` that runs migrations against the newly built image before the ECS service updates, halting the release if they fail.
|
|
45
|
+
|
|
46
|
+
## Inspecting Data Locally
|
|
47
|
+
|
|
48
|
+
For read-only inspection from your laptop (psql, DBeaver, Prisma Studio), open a secure tunnel with [`db connect`](/grada/cli/db/) instead of exposing the database — and run schema changes with [`db migrate`](/grada/cli/db/) so they execute inside the VPC.
|
|
49
|
+
|
|
50
|
+
## Choosing an Engine
|
|
51
|
+
|
|
52
|
+
When you answer "Yes" to the database prompt (or pass `--db-engine`), pick the engine that fits your workload:
|
|
53
|
+
|
|
54
|
+
| Engine | What you get | Cost |
|
|
55
|
+
| ------ | ------------ | ---- |
|
|
56
|
+
| `postgres` (default) | RDS PostgreSQL 16 on `db.t4g.micro` | ~$13.98/mo fixed |
|
|
57
|
+
| `mysql` | RDS MySQL 8.0 on `db.t4g.micro`; containers get `DB_PORT=3306` and a `DB_ENGINE=mysql` marker | ~$13.98/mo fixed |
|
|
58
|
+
| `aurora-postgresql` | Aurora PostgreSQL Serverless v2, scaling 0–2 ACU with auto-pause (takes the regional Aurora default version) | $0/mo idle compute (+$0.12/ACU-hr when active, plus storage) |
|
|
59
|
+
|
|
60
|
+
MySQL projects get a `mysql://` connection string from `db connect`, and `db migrate` synthesizes the matching `DATABASE_URL` scheme automatically. Aurora clusters are discovered as `<project-name>-db-cluster` by every `db` subcommand; backups and restores use cluster snapshots. The architecture preview and cost estimate reflect the provisioned engine.
|
|
61
|
+
|
|
62
|
+
## Importing Existing Data
|
|
63
|
+
|
|
64
|
+
Bringing a database from Heroku, Supabase, or another provider? [`db import`](/grada/cli/db/) streams a local dump (`--file`, including `.sql.gz` and Postgres `.dump` archives) or a live remote database (`--from`) into your isolated instance through a temporary SSM tunnel — the database is never exposed to do it. Credentials travel via `PGPASSWORD` / `MYSQL_PWD` and are masked in all output; take a [`db backup`](/grada/cli/db/) checkpoint first.
|