@grada-run/grada 0.0.1 → 0.33.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/e2e.yml +73 -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 +85 -0
- package/apps/docs/src/content/docs/cli/apply.md +35 -0
- package/apps/docs/src/content/docs/cli/db.md +200 -0
- package/apps/docs/src/content/docs/cli/destroy.md +35 -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 +33 -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 +87 -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 +99 -0
- package/apps/docs/src/content/docs/testing-strategy.md +37 -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 +107 -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/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/e2e-testing.md +50 -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/specs/test-suite-deduplication.md +42 -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 +130 -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 +128 -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 +78 -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 +2018 -0
- package/tests/ai.test.js +91 -0
- package/tests/apply.test.js +446 -0
- package/tests/args.test.js +86 -0
- package/tests/aws.test.js +244 -0
- package/tests/capabilities.test.js +304 -0
- package/tests/cli.test.js +29 -0
- package/tests/command.test.js +99 -0
- package/tests/commands-import.test.js +74 -0
- package/tests/db.test.js +2673 -0
- package/tests/destroy.test.js +365 -0
- package/tests/detector.test.js +79 -0
- package/tests/diagnose.test.js +765 -0
- package/tests/doctor.test.js +195 -0
- package/tests/domain.test.js +882 -0
- package/tests/drift.test.js +228 -0
- package/tests/e2e/helpers.js +122 -0
- package/tests/e2e/tier0.e2e.test.js +142 -0
- package/tests/e2e/tier1.live.e2e.test.js +118 -0
- package/tests/ecs.test.js +130 -0
- package/tests/eject.test.js +65 -0
- package/tests/exec.test.js +366 -0
- package/tests/gc.test.js +466 -0
- package/tests/generator.test.js +794 -0
- package/tests/headless.test.js +491 -0
- package/tests/helpers/clack.js +103 -0
- package/tests/helpers/console.js +41 -0
- package/tests/helpers/telemetry.js +37 -0
- package/tests/helpers/tmpdir.js +36 -0
- package/tests/lambda-ecr.test.js +185 -0
- package/tests/logs.test.js +436 -0
- package/tests/parser.test.js +160 -0
- package/tests/rds.test.js +244 -0
- package/tests/resolvers.test.js +279 -0
- package/tests/rollback.test.js +670 -0
- package/tests/secrets.test.js +729 -0
- package/tests/sleep-wake.test.js +998 -0
- package/tests/status.test.js +356 -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 +480 -0
- package/vitest.config.js +10 -0
- package/vitest.e2e.tier0.config.js +8 -0
- package/vitest.e2e.tier1.config.js +8 -0
- package/index.js +0 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: grada docs
|
|
3
|
+
description: Official developer portal for grada — concepts, guides, and CLI reference.
|
|
4
|
+
template: splash
|
|
5
|
+
tableOfContents: false
|
|
6
|
+
head:
|
|
7
|
+
- tag: style
|
|
8
|
+
content: |
|
|
9
|
+
/* Landing page: compact two-column hero, everything above the fold. */
|
|
10
|
+
#_top { display: none; }
|
|
11
|
+
.landing-hero { padding: 1.5rem 0; }
|
|
12
|
+
|
|
13
|
+
.sl-markdown-content .landing-grid {
|
|
14
|
+
display: grid;
|
|
15
|
+
grid-template-columns: 1fr 1fr;
|
|
16
|
+
gap: 2rem;
|
|
17
|
+
align-items: start;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Brute-force the top alignment to ignore Starlight's markdown margins */
|
|
23
|
+
.sl-markdown-content h1.landing-title,
|
|
24
|
+
.sl-markdown-content p.landing-intro {
|
|
25
|
+
margin-top: 0 !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.sl-markdown-content h1.landing-title { line-height: 1.1; }
|
|
29
|
+
.sl-markdown-content .landing-tagline { margin-top: 1rem !important; }
|
|
30
|
+
.landing-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1.5rem; }
|
|
31
|
+
|
|
32
|
+
.sl-markdown-content .landing-cards {
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-columns: repeat(3, 1fr);
|
|
35
|
+
gap: 1.5rem;
|
|
36
|
+
align-items: stretch;
|
|
37
|
+
margin-top: 2rem;
|
|
38
|
+
padding: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Force height propagation through any hidden MDX wrappers */
|
|
42
|
+
.sl-markdown-content .landing-cards > * {
|
|
43
|
+
margin: 0 !important;
|
|
44
|
+
height: 100% !important;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.sl-markdown-content .landing-cards .sl-link-card,
|
|
48
|
+
.sl-markdown-content .landing-cards .sl-link-card a {
|
|
49
|
+
height: 100% !important;
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.sl-markdown-content .landing-footnote {
|
|
55
|
+
margin-top: 2rem;
|
|
56
|
+
font-size: var(--sl-text-sm);
|
|
57
|
+
color: var(--sl-color-gray-2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (max-width: 50rem) {
|
|
61
|
+
.sl-markdown-content .landing-grid { grid-template-columns: 1fr; }
|
|
62
|
+
.sl-markdown-content .landing-cards { grid-template-columns: 1fr; }
|
|
63
|
+
}
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
import { LinkCard, LinkButton, Code } from '@astrojs/starlight/components';
|
|
67
|
+
|
|
68
|
+
<div class="landing-hero">
|
|
69
|
+
<div class="landing-grid">
|
|
70
|
+
<div>
|
|
71
|
+
<h1 class="landing-title">grada docs</h1>
|
|
72
|
+
<p class="landing-tagline">Provision production-ready AWS infrastructure and CI/CD pipelines in seconds.</p>
|
|
73
|
+
<div class="landing-actions">
|
|
74
|
+
<LinkButton href="/grada/guides/quickstart/">Get started in 5 minutes</LinkButton>
|
|
75
|
+
<LinkButton href="/grada/cli/init/" variant="minimal">CLI reference</LinkButton>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div>
|
|
79
|
+
<p class="landing-intro">`grada` turns your repo into a production-ready AWS deployment — Terraform, Docker, and CI/CD generated from your code:</p>
|
|
80
|
+
<Code code={`npx grada-run # scaffold Terraform, Dockerfile, workflows\nnpx grada-run apply # provision the ALB, cluster, and service\ngit push # build, scan, and roll out your image`} lang="bash" />
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="landing-cards">
|
|
86
|
+
<LinkCard
|
|
87
|
+
title="Deploying for the first time"
|
|
88
|
+
description="Follow the 5-minute Quickstart, then the CI/CD pipeline and first deploy."
|
|
89
|
+
href="/grada/guides/quickstart/"
|
|
90
|
+
/>
|
|
91
|
+
<LinkCard
|
|
92
|
+
title="Migrating from Vercel or Heroku"
|
|
93
|
+
description="Next.js, Astro, SvelteKit, and Procfile guides for moving to AWS Fargate."
|
|
94
|
+
href="/grada/migrations/nextjs-vercel-to-aws/"
|
|
95
|
+
/>
|
|
96
|
+
<LinkCard
|
|
97
|
+
title="Looking up a command"
|
|
98
|
+
description="Full CLI reference starting with npx grada-run."
|
|
99
|
+
href="/grada/cli/init/"
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<p class="landing-footnote">Supports NestJS, Next.js, Nuxt, Express, SvelteKit, Astro, FastAPI, Django, Rails, and Go — see <a href="/grada/guides/frameworks/">Supported Frameworks</a> · <a href="/grada/guides/examples/">Examples</a> · <a href="/grada/adrs/0001-s3-native-state-locking/">Architecture Decisions</a></p>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migrating Astro from Vercel to AWS Fargate"
|
|
3
|
+
description: "Switch the Astro adapter to Node standalone to leave Vercel for AWS Fargate."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
If you are seeing a warning from `grada` about your Astro adapter, it means your project is currently configured to build specifically for Vercel's proprietary serverless network.
|
|
7
|
+
|
|
8
|
+
To deploy Astro as a containerized application on standard AWS infrastructure, you simply need to switch to Astro's official Node.js adapter.
|
|
9
|
+
|
|
10
|
+
## How to Fix
|
|
11
|
+
|
|
12
|
+
### 1. Install the Node adapter
|
|
13
|
+
Run the following command in your terminal to swap out the Vercel adapter for the Node adapter:
|
|
14
|
+
|
|
15
|
+
\`\`\`bash
|
|
16
|
+
npm install @astrojs/node
|
|
17
|
+
npm uninstall @astrojs/vercel
|
|
18
|
+
\`\`\`
|
|
19
|
+
|
|
20
|
+
### 2. Update `astro.config.mjs`
|
|
21
|
+
Open your Astro configuration file and replace the Vercel import with the Node import.
|
|
22
|
+
|
|
23
|
+
**Before (Vercel Lock-in):**
|
|
24
|
+
\`\`\`javascript
|
|
25
|
+
import { defineConfig } from 'astro/config';
|
|
26
|
+
import vercel from '@astrojs/vercel/serverless';
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
output: 'server',
|
|
30
|
+
adapter: vercel(),
|
|
31
|
+
});
|
|
32
|
+
\`\`\`
|
|
33
|
+
|
|
34
|
+
**After (AWS Ready):**
|
|
35
|
+
\`\`\`javascript
|
|
36
|
+
import { defineConfig } from 'astro/config';
|
|
37
|
+
import node from '@astrojs/node';
|
|
38
|
+
|
|
39
|
+
export default defineConfig({
|
|
40
|
+
output: 'server',
|
|
41
|
+
adapter: node({
|
|
42
|
+
mode: 'standalone'
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
### 3. Deploy
|
|
48
|
+
That's it! Your Astro app is now decoupled from Vercel.
|
|
49
|
+
|
|
50
|
+
Run `npx grada-run apply` and the CLI will automatically package this standalone Node server into a hardened Docker container and deploy it to your AWS cluster.
|
|
51
|
+
|
|
52
|
+
## Next steps
|
|
53
|
+
|
|
54
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for what happens on `git push`.
|
|
55
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for Astro build requirements.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migrating from Heroku to AWS (Procfile Support)"
|
|
3
|
+
description: "Map Heroku Procfile web and worker processes to AWS ECS Fargate services."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
When migrating from Heroku or Render, you likely rely on a `Procfile` to define your application's architecture (e.g., a web server and a background worker like Celery or Sidekiq).
|
|
7
|
+
|
|
8
|
+
`grada` natively understands Heroku `Procfile` syntax and automatically translates it into a production-grade, multi-container AWS architecture.
|
|
9
|
+
|
|
10
|
+
## How it Works
|
|
11
|
+
|
|
12
|
+
When you run `npx grada-run`, the CLI scans your root directory for a `Procfile`.
|
|
13
|
+
|
|
14
|
+
### The `web` Process
|
|
15
|
+
If the CLI detects a `web:` declaration:
|
|
16
|
+
1. It overrides the default Docker `CMD`.
|
|
17
|
+
2. It provisions an AWS ECS Fargate service for this process.
|
|
18
|
+
3. It automatically wires this specific container to your public-facing Application Load Balancer (ALB) so it can receive internet traffic.
|
|
19
|
+
|
|
20
|
+
### The `worker` Process
|
|
21
|
+
If the CLI detects a `worker:` declaration:
|
|
22
|
+
1. It generates a completely separate ECS Fargate task definition and private service (`worker.tf`) running the same image with your worker command.
|
|
23
|
+
2. The service gets **no load balancer**, so nothing routes internet traffic to it — it still reaches your database, caches, and queues over the VPC network.
|
|
24
|
+
3. It shares the web container's secrets, database variables, and log group (worker entries carry the `worker` stream prefix), scaling independently of the web service.
|
|
25
|
+
|
|
26
|
+
## Example
|
|
27
|
+
|
|
28
|
+
**Your `Procfile`:**
|
|
29
|
+
```text
|
|
30
|
+
web: gunicorn myapp.wsgi
|
|
31
|
+
worker: celery -A myapp worker -l info
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**The Result:**
|
|
35
|
+
Running `grada` will automatically generate the Terraform required to spin up both containers simultaneously from the exact same Docker image, scaling them independently based on your needs.
|
|
36
|
+
|
|
37
|
+
## Next steps
|
|
38
|
+
|
|
39
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for what happens on `git push`.
|
|
40
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for Procfile and framework detection.
|
|
41
|
+
- [Background Workers](/grada/guides/background-workers/) for the worker service, SQS scale-to-zero, and day-2 operations.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migrating Next.js from Vercel to AWS Fargate"
|
|
3
|
+
description: "Add output: 'standalone' to run Next.js in a lean AWS Fargate container."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
If you are seeing a warning from `grada` about `output: 'standalone'`, your Next.js configuration is missing a crucial setting required for containerized environments.
|
|
7
|
+
|
|
8
|
+
By default, Next.js requires your entire `node_modules` folder to run the production server. This creates massive, bloated Docker containers that boot slowly and cost more to host. The `standalone` output mode tells Next.js to trace your code and bundle *only* the specific files and dependencies actually used in production, creating an ultra-lean deployment artifact.
|
|
9
|
+
|
|
10
|
+
## How to Fix
|
|
11
|
+
|
|
12
|
+
### 1. Update `next.config.js` (or `.mjs` / `.cjs`)
|
|
13
|
+
Open your Next.js configuration file in the root of your project and add `output: 'standalone'` to the configuration object.
|
|
14
|
+
|
|
15
|
+
**Before (Vercel Default):**
|
|
16
|
+
```javascript
|
|
17
|
+
/** @type {import('next').NextConfig} */
|
|
18
|
+
const nextConfig = {
|
|
19
|
+
reactStrictMode: true,
|
|
20
|
+
// Other existing config...
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default nextConfig;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**After (AWS Ready):**
|
|
27
|
+
```javascript
|
|
28
|
+
/** @type {import('next').NextConfig} */
|
|
29
|
+
const nextConfig = {
|
|
30
|
+
reactStrictMode: true,
|
|
31
|
+
output: 'standalone', // <-- Add this line
|
|
32
|
+
// Other existing config...
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default nextConfig;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. (Optional) Define a Health Check Route
|
|
39
|
+
AWS Application Load Balancers require a route to ping to ensure your app is healthy. If you don't already have one, create a simple API route in your app (e.g., `app/api/health/route.ts` for App Router, or `pages/api/health.ts` for Pages Router) that returns a `200 OK` status.
|
|
40
|
+
|
|
41
|
+
When running `grada`, choose **Advanced Configuration** and set your ALB Health Check Path to this route (e.g., `/api/health`).
|
|
42
|
+
|
|
43
|
+
### 3. Deploy
|
|
44
|
+
Your Next.js app is now perfectly optimized for AWS ECS Fargate!
|
|
45
|
+
|
|
46
|
+
Run `npx grada-run apply`. The CLI's generated `Dockerfile` will automatically target your new `.next/standalone` directory and deploy the optimized build to the cloud.
|
|
47
|
+
|
|
48
|
+
## Next steps
|
|
49
|
+
|
|
50
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for what happens on `git push`.
|
|
51
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for Next.js requirements.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migrating SvelteKit from Vercel to AWS Fargate"
|
|
3
|
+
description: "Switch SvelteKit to adapter-node to leave Vercel for AWS Fargate."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
If you are seeing a warning from `grada` about your SvelteKit adapter, your project is currently using `@sveltejs/adapter-auto` (which often defaults to Vercel) or the explicit `@sveltejs/adapter-vercel`.
|
|
7
|
+
|
|
8
|
+
These adapters are designed specifically for proprietary serverless edge networks. To run your SvelteKit app in a scalable, standard Docker container on AWS Fargate, you need to switch to Svelte's official Node adapter.
|
|
9
|
+
|
|
10
|
+
## How to Fix
|
|
11
|
+
|
|
12
|
+
### 1. Install the Node Adapter
|
|
13
|
+
Run the following command in your terminal to install the Node adapter and remove the Vercel/Auto adapter:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -D @sveltejs/adapter-node
|
|
17
|
+
npm uninstall @sveltejs/adapter-auto @sveltejs/adapter-vercel
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Update `svelte.config.js`
|
|
21
|
+
Open your `svelte.config.js` file and change the adapter import at the top of the file.
|
|
22
|
+
|
|
23
|
+
**Before (Locked into Vercel/Auto):**
|
|
24
|
+
```javascript
|
|
25
|
+
import adapter from '@sveltejs/adapter-auto'; // or '@sveltejs/adapter-vercel'
|
|
26
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
27
|
+
|
|
28
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
29
|
+
const config = {
|
|
30
|
+
preprocess: vitePreprocess(),
|
|
31
|
+
kit: {
|
|
32
|
+
adapter: adapter()
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default config;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**After (AWS Ready):**
|
|
40
|
+
```javascript
|
|
41
|
+
import adapter from '@sveltejs/adapter-node';
|
|
42
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
43
|
+
|
|
44
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
45
|
+
const config = {
|
|
46
|
+
preprocess: vitePreprocess(),
|
|
47
|
+
kit: {
|
|
48
|
+
adapter: adapter()
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default config;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Deploy
|
|
56
|
+
Your SvelteKit app is now decoupled!
|
|
57
|
+
|
|
58
|
+
Run `npx grada-run apply`. The CLI will automatically detect the standard Node build output, package it into a hardened Docker container, and deploy it to your AWS cluster.
|
|
59
|
+
|
|
60
|
+
## Next steps
|
|
61
|
+
|
|
62
|
+
- [CI/CD Pipeline & First Deploy](/grada/guides/cicd-pipeline/) for what happens on `git push`.
|
|
63
|
+
- [Supported Frameworks](/grada/guides/frameworks/) for SvelteKit adapter requirements.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Roadmap
|
|
3
|
+
description: Where grada has been and what comes next — completed phases and the current milestone.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Phase 1–3: The Core Engine (Completed)
|
|
7
|
+
- [x] **Core MVP:** Interactive CLI, ECS Fargate + ALB generation, CI/CD, and Secrets sync.
|
|
8
|
+
- [x] **Production Readiness:** CloudFront CDN edge distribution, native S3 state locking, and secure OIDC integration.
|
|
9
|
+
- [x] **Smart Experience:** Zero-config framework auto-discovery for static output directories.
|
|
10
|
+
- [x] **Trust & Observability:** DevSecOps Trivy scanning, automated 5XX alarms, 14-day log retention, and safe local overwrite protections.
|
|
11
|
+
|
|
12
|
+
### Phase 4: Trust Anchors & TAM Expansion (Completed)
|
|
13
|
+
- [x] **Ecosystem Distribution:** Native GitHub Marketplace Action for rapid discovery.
|
|
14
|
+
- [x] **Cost Transparency:** Pre-flight AWS cost estimator injected directly into the CLI wizard.
|
|
15
|
+
- [x] **Zero Vendor Lock-In:** Explicit `npx grada-run eject` command to safely strip `ManagedBy` tags and CLI metadata, leaving behind pure IaC.
|
|
16
|
+
- [x] **Heavy Backend Monoliths:** Hardened, unprivileged container adapters for Go, Nuxt.js, Django, and Rails, complete with automated zero-trust RDS PostgreSQL provisioning.
|
|
17
|
+
|
|
18
|
+
### Phase 5: The Activation Engine (Completed)
|
|
19
|
+
- [x] **Local Execution Wrapper:** Native `grada apply` command with terminal-optimized streaming to eliminate Terraform context switching.
|
|
20
|
+
- [x] **Ecosystem Integrations:** Official plugins published to the Astro Integrations directory (`astro-grada`) and Nuxt module registry (`nuxt-grada`).
|
|
21
|
+
|
|
22
|
+
### Phase 6: Migration & Trust Engine (Completed)
|
|
23
|
+
- [x] **Dry-Run Visualization:** Interactive pre-flight terminal UI with ASCII topology maps and precise, dynamic AWS cost estimation.
|
|
24
|
+
- [x] **PaaS Importers:** Auto-parse `vercel.json` and Heroku `Procfile` configurations to map routing rules, web commands, and background workers automatically.
|
|
25
|
+
- [x] **Docker Compose to ECS Translator:** Automatically converting a familiar local `docker-compose.yml` into production ECS task definitions.
|
|
26
|
+
- [x] **AI Agent Rulesets:** Publishing `.cursorrules` and Copilot instructions that teach AI assistants exactly how to utilize the CLI on the user's behalf.
|
|
27
|
+
|
|
28
|
+
### Phase 7: Team Workflows & Ecosystem Integrations (Completed)
|
|
29
|
+
*Focus: Enhance collaborative development and expand native support across major framework ecosystems.*
|
|
30
|
+
- [x] **Ephemeral PR Previews:** Generate GitHub Actions workflows that spin up temporary ECS Fargate tasks and post live preview URLs directly in pull request comments to streamline team code reviews.
|
|
31
|
+
- [x] **AI Context Synchronization:** Implement `grada sync-ai` to automatically generate `.cursorrules` and AI context files, ensuring coding assistants generate accurate deployment commands tailored to the project.
|
|
32
|
+
- [x] **Native Ecosystem Integrations:** Publish seamless, push-button plugins across major frameworks.
|
|
33
|
+
- [x] `vite-plugin-grada` (Live on NPM)
|
|
34
|
+
- [x] `svelte-adapter-grada` (SvelteKit adapter integration)
|
|
35
|
+
- [x] `cookiecutter-django-grada` (Listed on Django Packages)
|
|
36
|
+
- [x] `cookiecutter-fastapi-grada` (Cookiecutter for modern async Python)
|
|
37
|
+
- [x] `nest-grada` (Native `nest add` schematic for NestJS)
|
|
38
|
+
- [x] `rails-template-grada` (Zero-click Ruby on Rails application template)
|
|
39
|
+
- [x] **Automated Troubleshooting:** `grada diagnose` (alias: `wtf`) automatically analyzes common day-2 AWS operational issues (e.g., Fargate OOM kills, ALB 502s) directly from the terminal.
|
|
40
|
+
|
|
41
|
+
### Phase 8: Platform Hardening & Developer Experience (Completed)
|
|
42
|
+
*Focus: Solidify the core engine's reliability, prove security compliance, and establish documentation hub before introducing Day-2 operational commands.*
|
|
43
|
+
- [x] **Documentation Hub:** Launch a dedicated Astro Starlight documentation site featuring interactive architecture diagrams, core concept deep-dives, and detailed CLI references.
|
|
44
|
+
- [x] **Continuous Infrastructure Validation:** Implement a GitHub Actions matrix pipeline that automatically generates, compiles, and validates Terraform syntax (`terraform validate`, `tflint`) against all supported frameworks on every commit.
|
|
45
|
+
- [x] **Automated Security & Compliance Proving:** Integrate DevSecOps infrastructure scanning (`trivy` or `tfsec`) directly into the CI pipeline to mathematically guarantee zero-CVE, secure-by-default AWS provisioning.
|
|
46
|
+
- [x] **Integration Stability Suite:** Expand Vitest coverage to enforce strict contracts for headless execution flags (`--preconfigured`, `--headless`), ensuring seamless interoperability with third-party scaffolding tools.
|
|
47
|
+
|
|
48
|
+
### Phase 9: Day-2 Operations & Developer Retention (Completed)
|
|
49
|
+
*Focus: Uninterrupted Developer Flow. Deliver a seamless Day-2 environment where users maintain full infrastructure control without leaving the command line to troubleshoot.*
|
|
50
|
+
- [x] **Context-Aware Log Streaming:** `grada logs <service> --tail --error`. Implement a live stream using the CloudWatch Logs API to merge API/frontend logs in a color-coded terminal view, eliminating the need to navigate the AWS web console.
|
|
51
|
+
- [x] **1-Click Container Access:** `grada exec <service>`. Automatically drop the user into a secure bash shell inside a running Fargate container using AWS Systems Manager (SSM) Session Manager, abstracting away complex IAM trust policies and local agent requirements.
|
|
52
|
+
- [x] **Secure Secrets Sync & Rolling Restarts:** `grada secrets pull/audit`. Fetch vault payloads to a local `.env`, compare local vs. remote keys, and trigger rolling ECS restarts for value-only rotations.
|
|
53
|
+
- [x] **Secure Database Tunneling:** `grada db connect`. Utilize SSM Port Forwarding to open a secure `localhost` tunnel directly to your private RDS PostgreSQL instance, allowing tools like DBeaver or Prisma Studio to query production data without public internet exposure.
|
|
54
|
+
- [x] **Health & Alarm Dashboard:** `grada status`. Query the ECS Service status (Desired vs. Running tasks) and CloudWatch Alarms (e.g., ALB 5XX errors), printing a clear green/red operational status matrix directly in the terminal.
|
|
55
|
+
- [x] **Orphaned Resource Garbage Collection:** `grada gc`. Scan the AWS account for unattached Elastic IPs, abandoned ECR image layers, and lingering CloudWatch log groups left behind by PR previews or manual deletions, safely removing them to protect the user's AWS bill.
|
|
56
|
+
|
|
57
|
+
### Phase 10: Complete Day-0 to Day-N Lifecycle Mastery (Completed — 19/19)
|
|
58
|
+
**Goal:** Zero-Console Production Independence. Eliminate the final architectural, data, and operational triggers that force developers to open the AWS Management Console across the entire application lifecycle.
|
|
59
|
+
|
|
60
|
+
- [x] **Custom Domains & Automated SSL:** `grada domain add <domain>`. Automate Route 53 Hosted Zone bindings or provide an interactive External DNS verification flow (Cloudflare, Namecheap) with automated ACM TLS certificate issuance (including `us-east-1` validation for edge/CloudFront) and ALB listener routing.
|
|
61
|
+
- [x] **Instant One-Command Rollback:** `grada rollback [revision]`. List the last 5 deployed task revisions and instantly revert the live ECS service to a prior healthy revision in under 15 seconds, bypassing lengthy rebuild cycles during production regressions.
|
|
62
|
+
- [x] **Self-Healing Deployment Circuit Breakers:** Enable native ECS deployment circuit breakers (`deployment_circuit_breaker { enable = true, rollback = true }`) in Terraform, automatically rolling back failed container rollouts and broken health checks without operator intervention.
|
|
63
|
+
- [x] **Pre-Deploy Database Migration Gate:** Inject an isolated `aws ecs run-task` step into `.github/workflows/deploy.yml` to execute schema migrations (`prisma migrate deploy`, `alembic upgrade head`, `rails db:migrate`) against RDS inside the VPC before rolling out the new service revision, automatically halting the release if migrations fail.
|
|
64
|
+
- [x] **On-Demand Database Snapshots & Restore:** `grada db backup` and `grada db restore`. Provide instantaneous CLI wrappers around RDS manual snapshots and point-in-time recovery so developers can create pre-migration safety checkpoints or restore instances directly from the terminal.
|
|
65
|
+
- [x] **Transactional Email & DKIM Automation:** `grada add email:ses`. Provision Amazon SES Domain Identities, auto-inject the 3 required DKIM CNAME records into Route 53 (or output external DNS records), configure SPF/DMARC baselines, and attach least-privilege `ses:SendEmail` permissions to the ECS Task Role.
|
|
66
|
+
- [x] **Application Object Storage:** `grada add storage:s3`. Provision secure, private S3 buckets for asset uploads configured with CloudFront Origin Access Control (OAC), CORS rules, and presigned URL IAM policies injected directly into the container runtime.
|
|
67
|
+
- [x] **In-Memory Caching & Async Queues:** `grada add db:redis` (powered by cost-optimized AWS ElastiCache for Valkey/Redis) and `grada add queue:sqs`. Scaffold private in-memory cache clusters, SQS queues with dead-letter queues, and scale-to-zero background worker Fargate services driven by queue depth auto-scaling (`ApproximateNumberOfMessagesVisible`).
|
|
68
|
+
- [x] **Scheduled Cron Jobs:** `grada add cron`. EventBridge Scheduler rules that trigger one-off Fargate tasks on a cron schedule.
|
|
69
|
+
- [x] **Serverless NoSQL:** `grada add db:dynamodb`. Provision scale-to-zero DynamoDB (`PAY_PER_REQUEST`) tables with free VPC Gateway Endpoints and auto-wired IAM policies.
|
|
70
|
+
- [x] **Vector Databases:** `grada db enable-vector`. One-command `pgvector` provisioning on RDS PostgreSQL for AI/RAG embeddings without expensive OpenSearch clusters.
|
|
71
|
+
- [x] **Multi-Engine RDS & Aurora Scale-to-Zero:** Support PostgreSQL, MySQL, and Aurora Serverless v2 (`0 ACU` auto-pause) across `init`, `db connect`, `db backup`, and `db restore` with automatic URI formatting (`postgresql://` and `mysql://`).
|
|
72
|
+
- [x] **On-Demand Remote Migration Runner:** `grada db migrate [--cmd <command>]`. Launch an ephemeral, one-off ECS Fargate task inside the private VPC to execute ad-hoc schema migrations or seed scripts (`prisma`, `alembic`, `rails db:seed`), streaming stdout/stderr live to the terminal.
|
|
73
|
+
- [x] **Zero-Trust Database Ingestion:** `grada db import [--file <dump.sql> | --from <url>]`. Stream local SQL dumps or remote databases (Heroku, Supabase, Render, Railway) directly into the isolated private RDS instance via an automated background SSM tunnel.
|
|
74
|
+
- [x] **GenAI Primitives:** `grada add ai:bedrock`. Configure least-privilege IAM policies for invoking AWS Bedrock foundation models.
|
|
75
|
+
- [x] **Serverless Compute Primitives:** `grada --target lambda`. Provide an alternate AWS Lambda + API Gateway deployment target for scale-to-zero web workloads.
|
|
76
|
+
- [x] **Environment Hibernation & FinOps:** `grada sleep <env>` and `grada wake <env>`. Scale ECS task counts to zero, stop non-production RDS instances, guard against the AWS 7-day RDS auto-restart behavior, and display estimated hourly savings to eliminate idle staging costs.
|
|
77
|
+
- [x] **Scheduled IaC Drift Detection:** `grada drift` and `--setup-ci-drift`. Generate an automated GitHub Action that periodically executes `terraform plan -detailed-exitcode` against live AWS infrastructure, opening GitHub Issues or dispatching Slack notifications when out-of-band console changes occur.
|
|
78
|
+
- [x] **Dependency-Aware Init:** Scan manifests for database, worker, migration, and addon signals before prompting — pre-selecting the database question, pre-filling the worker command, pre-checking detected addons with evidence, and offering the pre-deploy migration gate — with `--with` for one-pass headless composition.
|
|
79
|
+
|
|
80
|
+
### Phase 11: The `grada.run` Rebrand, Daily Observability & Agentic Ecosystem (Current)
|
|
81
|
+
**Goal:** Transition the platform identity to **Grada (`grada.run`)**, close the daily observability gap with zero-cost CloudWatch Golden Signals, eliminate cross-command state-transition bugs, and launch the native MCP and AI Agent Plugin ecosystem.
|
|
82
|
+
|
|
83
|
+
- [x] **Unified Brand & Binary Transition (`grada`):** Ship the `grada` binary alongside `grada-run` (plus a deprecated `deploy-stack` alias) and publish the `@grada-run/grada` scoped alias on release, keeping existing deployments working through transparent dual-read fallbacks for AWS tags, local state ledgers (`.grada/` + `.deploy-stack/`), machine markers, doc ownership markers (`GRADA.md` + `DEPLOY-STACK.md`), and environment variables. (Verified live.)
|
|
84
|
+
- [ ] **AI-Driven Edge-Case & State Transition Audit:** Run a systematic codebase audit tracing multi-step lifecycle mutations across both `--target ecs` and `--target lambda` (e.g., scaffold with `--db-engine aurora-postgresql` → `add queue:sqs` → `add cron` → `db enable-vector` → `sleep` → `wake` → `drift` → `rollback` → `eject` → `destroy`), patching race conditions, partial Terraform state locks, and UX dead ends.
|
|
85
|
+
- [x] **Two-Tier E2E Harness & Automation Bypasses:** Ship the black-box harness (`tests/e2e/`, Tier 0 mock-AWS suite on every PR, Tier 1 live `init` → `apply` → `status` → `destroy` lifecycle on a nightly schedule) plus `--auto-approve`/`--yes`/`--headless` bypasses for `apply`, `destroy`, and `eject`, replacing the planned LocalStack approach.
|
|
86
|
+
- [ ] **Deterministic Suite & Flaky Test Elimination:** Isolate network/loopback and SDK mocks in the Vitest suite, eliminate the timing-dependent loopback failure, and record first-green Tier 0 (PR) and Tier 1 (nightly) runs.
|
|
87
|
+
- [ ] **Live Service Acceptance (Tier 2 E2E):** Provision each add-on capability on real AWS (nightly) and verify runtime behavior — SQS send/receive + DLQ, DynamoDB put/get, Redis connectivity, S3 presigned-URL flow, SES send, Bedrock invoke, cron scheduling — with per-service setup/assert/teardown and spend caps.
|
|
88
|
+
- [ ] **Multi-Stage Dockerfile Hardening:** Refactor generated Dockerfiles to use multi-stage builds (e.g., `node:22-alpine AS builder` → `distroless/nodejs`), explicitly stripping package managers (`npm`, `yarn`) from the final runtime image to mathematically eliminate `HIGH`/`CRITICAL` vulnerability scanner noise on Day-0.
|
|
89
|
+
- [x] **Test Suite Deduplication & Hygiene:** Extract the hand-rolled `@clack/prompts` and `telemetry` mocks currently duplicated across 15+ test files into a centralized `tests/helpers/` directory to shrink maintenance surface area without dropping the 1,000+ test coverage count.
|
|
90
|
+
- [ ] **Golden Signals Live Telemetry & Alert Webhooks:** Upgrade `grada status` (and `grada status --watch`) to surface real-time CloudWatch Golden Signals (ECS CPU/Memory %, ALB requests/min, p95 latency, 5xx count, and RDS connections / Aurora ACUs) at $0 extra AWS cost, and add `grada alerts` to wire CloudWatch 5xx alarms and container crash events directly to Slack, Discord, or email.
|
|
91
|
+
- [ ] **Architecture Decision Records (ADRs) & Docs Audit:** Review and standardize all ADRs and Astro Starlight documentation under the `grada` brand to ensure every Phase 9–11 command, flag, compute target (`ecs` and `lambda`), and IAM security boundary is accurately documented with zero stale references.
|
|
92
|
+
- [ ] **Zero-Compute Static Target (`--target static`):** Provide a dedicated target for Vite SPAs, Astro SSG, and Next.js static exports that bypasses compute entirely, deploying pre-built assets directly to an S3 bucket fronted by CloudFront.
|
|
93
|
+
- [ ] **Native MCP Server Mode (`grada mcp`):** Embed a Model Context Protocol server directly inside the CLI binary exposing deterministic Day-1 (`analyze_stack`, `estimate_cost`, `add_primitive`) and Day-2 (`stack_status` with Golden Signals, `diagnose_stack`, `fetch_error_logs`, `audit_secrets`, `check_drift`) tools to AI coding assistants.
|
|
94
|
+
- [ ] **Claude Code, Cursor & Codex Plugin Manifests:** Package `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and `SKILL.md` playbooks so developers can install Grada natively from the Cursor Marketplace and Claude Code (`/plugin install`).
|
|
95
|
+
- [ ] **Automated IDE Guardrail Hooks:** Configure agent plugin hooks that automatically run `terraform validate` after `.tf` edits and prompt `grada secrets audit` whenever new keys are added to `.env` / `.env.local`.
|
|
96
|
+
- [ ] **Production Flagship Blueprint (`saas-starter`):** Publish a full-stack, production-ready SaaS reference repository (Next.js App Router + Aurora Serverless v2 PostgreSQL + Valkey/Redis + SES Transactional Email + OIDC PR Previews) deployable in one command with `grada`.
|
|
97
|
+
- [ ] **Production AI Blueprint (`ai-worker`):** Publish an async AI reference repository (FastAPI + AWS Bedrock + Aurora `pgvector` + SQS scale-to-zero worker + S3 presigned ingestion) demonstrating enterprise RAG without OpenSearch costs.
|
|
98
|
+
- [ ] **Serverless Scale-to-Zero Blueprint (`grada-lambda-fastapi`):** Publish a reference repository demonstrating the new `--target lambda` container image workflow with AWS Lambda Web Adapter, API Gateway HTTP API v2, and CloudFront.
|
|
99
|
+
- [ ] **High-Conversion `grada.run` Launch Site:** Ship the flagship marketing front-end above the Starlight docs featuring interactive terminal demos (`grada init`, `grada status --watch`, `grada mcp`), a live PaaS-to-AWS cost savings calculator, and a visual Day-0 to Day-N capability matrix.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Testing Strategy
|
|
3
|
+
description: How grada prevents regressions — unit tests, snapshot harness, API mocking, and CI validation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
To ensure zero regressions in infrastructure generation and safe local execution, `grada` relies on a multi-layered testing strategy split between fast local snapshots and rigid CI/CD validation.
|
|
7
|
+
|
|
8
|
+
## 1. Unit & argument testing
|
|
9
|
+
We use pure Node.js unit tests (via Vitest) to validate the CLI argument parser (`src/core/parser.js`). This ensures that flags (like `--headless` or `--no-telemetry`) are routed correctly and never hijack positional arguments like file paths.
|
|
10
|
+
|
|
11
|
+
## 1.5. Ecosystem integration contracts
|
|
12
|
+
Because `grada` acts as the underlying engine for ecosystem wrappers (e.g., `nest-grada`, `cookiecutter-fastapi`), we strictly test execution flags that bypass interactive prompts (written contract: `specs/integration-suite.md`, enforced by `tests/headless.test.js`):
|
|
13
|
+
* **Headless Validation:** Vitest deep-mocks `@clack/prompts` — the only interactive prompt library the CLI uses — and asserts that when `--headless` and `--preconfigured` are passed (e.g., `--framework=nestjs --port=3000`), none of its prompt functions (`text`, `select`, `multiselect`, `confirm`, `group`) ever fire and no interactive warnings are thrown. The suite also asserts flag values win over interactive defaults in the generated `terraform/main.tf` and `Dockerfile`, running end to end inside a temp directory so no files pollute the repo. This guarantees stability for automated ecosystem integrations.
|
|
14
|
+
|
|
15
|
+
## 2. Infrastructure snapshot harness (the static contract)
|
|
16
|
+
Because `grada` generates highly dynamic Terraform (`.tf`), GitHub Actions (`.yml`), and `Dockerfile` configurations, we use **Vitest Snapshots** to lock in the expected text outputs.
|
|
17
|
+
* **The Matrix:** The test suite generates dummy projects across 11 architectural topologies (including Django, Rails, Go, Nuxt, Next.js, SvelteKit, and Vercel/Heroku migrations).
|
|
18
|
+
* **Negative Testing:** The suite explicitly checks for the *absence* of files (e.g., ensuring `database.tf` or `worker.tf` are not generated for static sites).
|
|
19
|
+
* **Updating Snapshots:** If a template change is intentional, developers must run `npm run test:update` to overwrite the baseline `__snapshots__`.
|
|
20
|
+
|
|
21
|
+
## 3. External API mocking
|
|
22
|
+
To ensure tests run sub-second and deterministically without requiring real AWS credentials, we intercept network boundaries. Shared mock factories live in `tests/helpers/` (`clack.js` for `@clack/prompts`, `telemetry.js` for PostHog tracking, `console.js` for process/console spies, `tmpdir.js` for fixture directories) so new suites reuse one-liner `vi.mock` delegations instead of hand-rolling mocks:
|
|
23
|
+
* **AWS Secrets Manager:** `tests/secrets.test.js` uses Vitest's `vi.hoisted()` and `vi.mock()` to intercept `@aws-sdk/client-secrets-manager` (plus an injected ECS client for the restart path). This verifies push/pull/audit payload handling, key-change detection, and network exceptions (like `ResourceNotFoundException`) completely offline.
|
|
24
|
+
* **ECS & CloudWatch Logs:** `tests/diagnose.test.js` injects mock ECS/CloudWatch clients to verify failure analysis (stopped reasons, exit codes, log extraction) and behavior contracts — e.g., expired sessions (`UnrecognizedClientException`) exit gracefully with code 1, and unrecognized `secrets push` filenames fall back to `.env` with a warning.
|
|
25
|
+
* **Telemetry:** PostHog tracking is mocked to prevent test executions from polluting production analytics.
|
|
26
|
+
|
|
27
|
+
## 4. Continuous integration & execution validation (CI)
|
|
28
|
+
While Vitest proves the CLI generates the *correct* files, GitHub Actions proves those files *actually work*. Unit and snapshot tests are gated via `.github/workflows/test.yml`; live template compilation is gated via `.github/workflows/iac-validation.yml`.
|
|
29
|
+
* **Phase 1 (Generation):** Vitest runs unit and snapshot tests to verify the CLI contract.
|
|
30
|
+
* **Phase 2 (Static Application Security Testing - SAST):** CI runs a pinned Trivy filesystem scan (`aquasecurity/trivy-action` by SHA) against each generated project directory, writing advisory `trivy-fs-results.txt` reports (`HIGH,CRITICAL`, `exit-code: 0`) instead of failing the build.
|
|
31
|
+
* **Phase 3 (IaC Validation):** The `iac-validation` matrix workflow scaffolds all 10 supported frameworks headlessly (`--headless --preconfigured`), then runs `terraform init -backend=false` + `terraform validate`, `tflint`, the advisory filesystem scan, a stripped-Dockerfile `docker build`, and an advisory container-image scan (`trivy-image-results.txt`).
|
|
32
|
+
* **Phase 4 (Release gate):** `.github/workflows/publish.yml` reuses `iac-validation.yml` via `workflow_call` as a `validate` job; `build-and-publish` has `needs: [validate]`, so NPM publishing on release is blocked until the full matrix passes.
|
|
33
|
+
|
|
34
|
+
## 5. End-to-end lifecycle testing
|
|
35
|
+
Black-box suites under `tests/e2e/` execute the real `bin/cli.js` via `child_process` with stdin closed (a prompt crashes loudly instead of hanging) and `DO_NOT_TRACK=1`. They are excluded from the default `npm test` run and have dedicated configs:
|
|
36
|
+
* **Tier 0 (`npm run test:e2e:tier0`, every PR):** mock-AWS scaffold checks (`init` for ECS and Lambda targets, the full 7-capability `add` matrix plus an `init --with` composition, `terraform validate`), local checks (`doctor`, `eject`), and failure-path contracts (clean exit-1 shapes, no stack traces). Runs in `.github/workflows/e2e.yml` alongside Tier 1.
|
|
37
|
+
* **Tier 1 (`npm run test:e2e:tier1`, nightly/manual only):** the full live lifecycle (`init` → `apply --auto-approve` → `status` with a retry-until-healthy loop → `destroy --yes`) against real AWS via OIDC, skipping gracefully without credentials.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineCollection } from 'astro:content';
|
|
2
|
+
import { docsLoader } from '@astrojs/starlight/loaders';
|
|
3
|
+
import { docsSchema } from '@astrojs/starlight/schema';
|
|
4
|
+
|
|
5
|
+
export const collections = {
|
|
6
|
+
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
7
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Make all base text slightly smaller */
|
|
3
|
+
--sl-text-base: 0.95rem;
|
|
4
|
+
--sl-line-height: 1.6;
|
|
5
|
+
|
|
6
|
+
/* Shrink the headings */
|
|
7
|
+
--sl-text-h1: 2.2rem;
|
|
8
|
+
--sl-text-h2: 1.75rem;
|
|
9
|
+
--sl-text-h3: 1.35rem;
|
|
10
|
+
|
|
11
|
+
/* Tighten the left sidebar padding */
|
|
12
|
+
--sl-nav-pad-y: 0.25rem;
|
|
13
|
+
--sl-nav-gap: 0.5rem;
|
|
14
|
+
}
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { mainStack } from '../src/commands/init.js';
|
|
4
|
+
import { destroyStack } from '../src/commands/destroy.js';
|
|
5
|
+
import { runDoctor } from '../src/commands/doctor.js';
|
|
6
|
+
import { pushSecrets, pullSecrets, auditSecrets } from '../src/commands/secrets.js';
|
|
7
|
+
import { ejectStack } from '../src/commands/eject.js';
|
|
8
|
+
import { applyStack } from '../src/commands/apply.js';
|
|
9
|
+
import { runDiagnose } from '../src/commands/diagnose.js';
|
|
10
|
+
import { syncAi } from '../src/commands/sync-ai.js';
|
|
11
|
+
import { runLogs, parseLogsArgs } from '../src/commands/logs.js';
|
|
12
|
+
import { runStatus, parseStatusArgs } from '../src/commands/status.js';
|
|
13
|
+
import { runExec, parseExecArgs } from '../src/commands/exec.js';
|
|
14
|
+
import { runDb } from '../src/commands/db.js';
|
|
15
|
+
import { runRollback, parseRollbackArgs } from '../src/commands/rollback.js';
|
|
16
|
+
import { runGc, parseGcArgs } from '../src/commands/gc.js';
|
|
17
|
+
import { runAdd, parseAddArgs } from '../src/commands/add.js';
|
|
18
|
+
import { runDomain, parseDomainArgs } from '../src/commands/domain.js';
|
|
19
|
+
import { runSleep, parseSleepArgs } from '../src/commands/sleep.js';
|
|
20
|
+
import { runWake, parseWakeArgs } from '../src/commands/wake.js';
|
|
21
|
+
import { runDrift, parseDriftArgs } from '../src/commands/drift.js';
|
|
22
|
+
import { parseCliArgs } from '../src/core/parser.js';
|
|
23
|
+
|
|
24
|
+
const HELP_TEXT = [
|
|
25
|
+
'grada — Provision production-ready AWS infrastructure in seconds.',
|
|
26
|
+
'',
|
|
27
|
+
'Usage:',
|
|
28
|
+
' grada [command] [options]',
|
|
29
|
+
'',
|
|
30
|
+
'Commands:',
|
|
31
|
+
' init Provision infrastructure and CI/CD pipelines',
|
|
32
|
+
' apply Apply infrastructure changes (--auto-approve)',
|
|
33
|
+
' destroy Tear down infrastructure (--yes)',
|
|
34
|
+
' doctor Run pre-flight dependency checks',
|
|
35
|
+
' logs [service] Stream CloudWatch logs (--tail, -f/--follow, --error, --since, --region)',
|
|
36
|
+
' status Service health dashboard (--region, --json)',
|
|
37
|
+
' rollback [rev] Roll back ECS service to a previous task revision',
|
|
38
|
+
' exec Open an interactive shell in a running container (--cluster, --service, --container, --command, --region)',
|
|
39
|
+
' db connect Open a secure local tunnel to your database (--port, --show-credentials, --workspace, --region)',
|
|
40
|
+
' db enable-vector Enable the pgvector extension via a one-off ECS task (--task-def, --timeout)',
|
|
41
|
+
' db import Import a SQL dump into your database (--file, --from, --yes)',
|
|
42
|
+
' db migrate Run database migrations in a one-off ECS task (--cmd, --task-def, --timeout, --setup-ci)',
|
|
43
|
+
' db backup Create an RDS snapshot checkpoint (--id, --timeout, --no-wait)',
|
|
44
|
+
' db restore Restore the database from a snapshot ([snapshot-id], --yes)',
|
|
45
|
+
' gc Discover and delete orphaned ECR images, log groups, and Elastic IPs (--region)',
|
|
46
|
+
' sleep [env] Scale ECS services to zero and stop RDS to save costs (--skip-db, --yes)',
|
|
47
|
+
' wake [env] Start RDS and restore ECS desired counts (--skip-db, --no-wait)',
|
|
48
|
+
' drift Detect Terraform drift locally or scaffold scheduled checks (--setup)',
|
|
49
|
+
' add <capability> Provision a modular addon (storage:s3, db:dynamodb, db:redis, queue:sqs, ai:bedrock, email:ses, cron) [--model <id>, --list-models, --refresh]',
|
|
50
|
+
' domain add <domain> Provision a custom domain with automated ACM TLS (--zone-id, --activate)',
|
|
51
|
+
' domain verify|status|remove Activate, inspect, or remove the custom domain',
|
|
52
|
+
' secrets push Push environment secrets',
|
|
53
|
+
' secrets pull Pull environment secrets',
|
|
54
|
+
' secrets audit Audit local vs remote secrets drift',
|
|
55
|
+
' eject Eject to self-managed configs (--yes)',
|
|
56
|
+
' sync-ai Sync AI assistant rules',
|
|
57
|
+
'',
|
|
58
|
+
'Init options:',
|
|
59
|
+
' --target <ecs|lambda> Compute architecture: always-on Fargate + ALB (~$31/mo flat, best for steady traffic) or scale-to-zero Lambda + API Gateway ($0/mo idle, best for sporadic traffic). Tradeoffs: Stack Architecture guide → Fargate vs Lambda.',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const rawArgs = process.argv.slice(2);
|
|
63
|
+
const parsed = parseCliArgs(rawArgs);
|
|
64
|
+
|
|
65
|
+
if (parsed.hasNoTelemetry) {
|
|
66
|
+
process.env.DO_NOT_TRACK = '1';
|
|
67
|
+
}
|
|
68
|
+
process.env.CLI_COMMAND = parsed.baseCommand;
|
|
69
|
+
|
|
70
|
+
const { positionalArgs, isHeadless, isDryRun, isPreconfigured, autoApprove, yes: confirmYes, headlessOptions, initOptions } = parsed;
|
|
71
|
+
|
|
72
|
+
function parseRegionFlag(args) {
|
|
73
|
+
for (let i = 0; i < args.length; i++) {
|
|
74
|
+
if (args[i] === '--region' && i + 1 < args.length) return args[i + 1];
|
|
75
|
+
if (args[i].startsWith('--region=')) return args[i].slice('--region='.length);
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Dispatch guard: every command promise ends here so an unexpected rejection
|
|
81
|
+
// prints the error and exits non-zero instead of surfacing as an unhandled
|
|
82
|
+
// rejection with a stack trace and an unpredictable exit code.
|
|
83
|
+
function runCommand(promise) {
|
|
84
|
+
promise.catch((error) => {
|
|
85
|
+
console.error(error);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (positionalArgs[0] === 'secrets' && positionalArgs[1] === 'push') {
|
|
91
|
+
const envFile = positionalArgs[2] || '.env';
|
|
92
|
+
const projectName = path.basename(process.cwd());
|
|
93
|
+
runCommand(pushSecrets(envFile, projectName, { isHeadless, region: parseRegionFlag(rawArgs) }));
|
|
94
|
+
} else if (positionalArgs[0] === 'secrets' && positionalArgs[1] === 'pull') {
|
|
95
|
+
const envFile = positionalArgs[2] || '.env';
|
|
96
|
+
const projectName = path.basename(process.cwd());
|
|
97
|
+
runCommand(pullSecrets(envFile, projectName, { isHeadless, region: parseRegionFlag(rawArgs) }));
|
|
98
|
+
} else if (positionalArgs[0] === 'secrets' && positionalArgs[1] === 'audit') {
|
|
99
|
+
const envFile = positionalArgs[2] || '.env';
|
|
100
|
+
const projectName = path.basename(process.cwd());
|
|
101
|
+
runCommand(auditSecrets(envFile, projectName, { region: parseRegionFlag(rawArgs) }));
|
|
102
|
+
} else if (positionalArgs[0] === 'apply') {
|
|
103
|
+
runCommand(applyStack({ isDryRun, ...(autoApprove ? { autoApprove: true } : {}), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
104
|
+
} else if (positionalArgs[0] === 'doctor') {
|
|
105
|
+
runCommand(runDoctor());
|
|
106
|
+
} else if (positionalArgs[0] === 'destroy') {
|
|
107
|
+
runCommand(destroyStack({ ...(confirmYes ? { yes: true } : {}), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
108
|
+
} else if (positionalArgs[0] === 'eject') {
|
|
109
|
+
runCommand(ejectStack({ ...(confirmYes ? { yes: true } : {}), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
110
|
+
} else if (positionalArgs[0] === 'sync-ai') {
|
|
111
|
+
runCommand(syncAi());
|
|
112
|
+
} else if (positionalArgs[0] === 'diagnose' || positionalArgs[0] === 'wtf') {
|
|
113
|
+
runCommand(runDiagnose(headlessOptions));
|
|
114
|
+
} else if (positionalArgs[0] === 'logs') {
|
|
115
|
+
runCommand(runLogs(parseLogsArgs(rawArgs)));
|
|
116
|
+
} else if (positionalArgs[0] === 'status') {
|
|
117
|
+
runCommand(runStatus(parseStatusArgs(rawArgs)));
|
|
118
|
+
} else if (positionalArgs[0] === 'rollback') {
|
|
119
|
+
runCommand(runRollback({ ...parseRollbackArgs(rawArgs), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
120
|
+
} else if (positionalArgs[0] === 'exec') {
|
|
121
|
+
runCommand(runExec(parseExecArgs(rawArgs)));
|
|
122
|
+
} else if (positionalArgs[0] === 'db') {
|
|
123
|
+
runCommand(runDb(rawArgs, { ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
124
|
+
} else if (positionalArgs[0] === 'gc') {
|
|
125
|
+
runCommand(runGc(parseGcArgs(rawArgs)));
|
|
126
|
+
} else if (positionalArgs[0] === 'add') {
|
|
127
|
+
runCommand(runAdd(parseAddArgs(rawArgs)));
|
|
128
|
+
} else if (positionalArgs[0] === 'domain') {
|
|
129
|
+
runCommand(runDomain(parseDomainArgs(rawArgs)));
|
|
130
|
+
} else if (positionalArgs[0] === 'sleep') {
|
|
131
|
+
runCommand(runSleep({ ...parseSleepArgs(rawArgs), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
132
|
+
} else if (positionalArgs[0] === 'wake') {
|
|
133
|
+
runCommand(runWake({ ...parseWakeArgs(rawArgs), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
134
|
+
} else if (positionalArgs[0] === 'drift') {
|
|
135
|
+
runCommand(runDrift({ ...parseDriftArgs(rawArgs), ...(isHeadless ? { isHeadless: true } : {}) }));
|
|
136
|
+
} else if (positionalArgs[0] === 'help' || rawArgs.includes('--help') || rawArgs.includes('-h')) {
|
|
137
|
+
console.log(HELP_TEXT.join('\n'));
|
|
138
|
+
} else {
|
|
139
|
+
runCommand(mainStack({ isHeadless, isPreconfigured, headlessOptions, initOptions }));
|
|
140
|
+
}
|