thevoidforge 21.0.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/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +20 -0
- package/dist/scripts/voidforge.js +404 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +133 -0
- package/dist/wizard/api/blueprint.d.ts +45 -0
- package/dist/wizard/api/blueprint.js +184 -0
- package/dist/wizard/api/cloud-providers.d.ts +16 -0
- package/dist/wizard/api/cloud-providers.js +363 -0
- package/dist/wizard/api/credentials.d.ts +1 -0
- package/dist/wizard/api/credentials.js +258 -0
- package/dist/wizard/api/danger-room.d.ts +18 -0
- package/dist/wizard/api/danger-room.js +401 -0
- package/dist/wizard/api/deploy.d.ts +4 -0
- package/dist/wizard/api/deploy.js +164 -0
- package/dist/wizard/api/prd.d.ts +1 -0
- package/dist/wizard/api/prd.js +363 -0
- package/dist/wizard/api/project.d.ts +1 -0
- package/dist/wizard/api/project.js +239 -0
- package/dist/wizard/api/projects.d.ts +6 -0
- package/dist/wizard/api/projects.js +648 -0
- package/dist/wizard/api/provision.d.ts +4 -0
- package/dist/wizard/api/provision.js +535 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +241 -0
- package/dist/wizard/api/users.d.ts +6 -0
- package/dist/wizard/api/users.js +244 -0
- package/dist/wizard/api/war-room.d.ts +14 -0
- package/dist/wizard/api/war-room.js +45 -0
- package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
- package/dist/wizard/lib/ad-platform-core.js +1 -0
- package/dist/wizard/lib/adapters/index.d.ts +52 -0
- package/dist/wizard/lib/adapters/index.js +38 -0
- package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
- package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
- package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
- package/dist/wizard/lib/adapters/sandbox.js +174 -0
- package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
- package/dist/wizard/lib/adapters/stripe.js +143 -0
- package/dist/wizard/lib/adapters/types.d.ts +9 -0
- package/dist/wizard/lib/adapters/types.js +10 -0
- package/dist/wizard/lib/agent-memory.d.ts +36 -0
- package/dist/wizard/lib/agent-memory.js +114 -0
- package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
- package/dist/wizard/lib/anomaly-detection.js +122 -0
- package/dist/wizard/lib/anthropic.d.ts +21 -0
- package/dist/wizard/lib/anthropic.js +105 -0
- package/dist/wizard/lib/asset-scanner.d.ts +23 -0
- package/dist/wizard/lib/asset-scanner.js +107 -0
- package/dist/wizard/lib/audit-log.d.ts +23 -0
- package/dist/wizard/lib/audit-log.js +70 -0
- package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
- package/dist/wizard/lib/autonomy-controller.js +183 -0
- package/dist/wizard/lib/body-parser.d.ts +2 -0
- package/dist/wizard/lib/body-parser.js +36 -0
- package/dist/wizard/lib/build-analytics.d.ts +39 -0
- package/dist/wizard/lib/build-analytics.js +91 -0
- package/dist/wizard/lib/build-step.d.ts +21 -0
- package/dist/wizard/lib/build-step.js +104 -0
- package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
- package/dist/wizard/lib/campaign-proposer.js +180 -0
- package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
- package/dist/wizard/lib/campaign-state-machine.js +114 -0
- package/dist/wizard/lib/ci-generator.d.ts +14 -0
- package/dist/wizard/lib/ci-generator.js +187 -0
- package/dist/wizard/lib/claude-merge.d.ts +38 -0
- package/dist/wizard/lib/claude-merge.js +115 -0
- package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/erd-gen.js +98 -0
- package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
- package/dist/wizard/lib/codegen/integrations.js +189 -0
- package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
- package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
- package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
- package/dist/wizard/lib/codegen/prisma-types.js +44 -0
- package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/seed-gen.js +128 -0
- package/dist/wizard/lib/compliance.d.ts +51 -0
- package/dist/wizard/lib/compliance.js +112 -0
- package/dist/wizard/lib/correlation-engine.d.ts +59 -0
- package/dist/wizard/lib/correlation-engine.js +151 -0
- package/dist/wizard/lib/cost-estimator.d.ts +22 -0
- package/dist/wizard/lib/cost-estimator.js +72 -0
- package/dist/wizard/lib/cost-tracker.d.ts +27 -0
- package/dist/wizard/lib/cost-tracker.js +37 -0
- package/dist/wizard/lib/daemon-aggregator.d.ts +71 -0
- package/dist/wizard/lib/daemon-aggregator.js +204 -0
- package/dist/wizard/lib/daemon-core.d.ts +6 -0
- package/dist/wizard/lib/daemon-core.js +5 -0
- package/dist/wizard/lib/dashboard-data.d.ts +132 -0
- package/dist/wizard/lib/dashboard-data.js +336 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
- package/dist/wizard/lib/dashboard-ws.js +91 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +234 -0
- package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
- package/dist/wizard/lib/deploy-coordinator.js +86 -0
- package/dist/wizard/lib/deploy-log.d.ts +28 -0
- package/dist/wizard/lib/deploy-log.js +52 -0
- package/dist/wizard/lib/desktop-notify.d.ts +27 -0
- package/dist/wizard/lib/desktop-notify.js +98 -0
- package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
- package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
- package/dist/wizard/lib/dns/types.d.ts +22 -0
- package/dist/wizard/lib/dns/types.js +4 -0
- package/dist/wizard/lib/document-discovery.d.ts +33 -0
- package/dist/wizard/lib/document-discovery.js +145 -0
- package/dist/wizard/lib/env-validator.d.ts +14 -0
- package/dist/wizard/lib/env-validator.js +205 -0
- package/dist/wizard/lib/env-writer.d.ts +13 -0
- package/dist/wizard/lib/env-writer.js +26 -0
- package/dist/wizard/lib/exec.d.ts +30 -0
- package/dist/wizard/lib/exec.js +52 -0
- package/dist/wizard/lib/experiment.d.ts +70 -0
- package/dist/wizard/lib/experiment.js +169 -0
- package/dist/wizard/lib/extensions.d.ts +20 -0
- package/dist/wizard/lib/extensions.js +183 -0
- package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
- package/dist/wizard/lib/financial/adapter-factory.js +225 -0
- package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
- package/dist/wizard/lib/financial/billing/base.js +1 -0
- package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
- package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
- package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
- package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
- package/dist/wizard/lib/financial/campaign/base.js +1 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +42 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +40 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -0
- package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
- package/dist/wizard/lib/financial/funding-auto.js +52 -0
- package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
- package/dist/wizard/lib/financial/funding-policy.js +179 -0
- package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
- package/dist/wizard/lib/financial/platform-planner.js +134 -0
- package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
- package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
- package/dist/wizard/lib/financial/registry.d.ts +22 -0
- package/dist/wizard/lib/financial/registry.js +26 -0
- package/dist/wizard/lib/financial/reporting.d.ts +96 -0
- package/dist/wizard/lib/financial/reporting.js +198 -0
- package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
- package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
- package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
- package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
- package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
- package/dist/wizard/lib/financial/treasury-planner.js +128 -0
- package/dist/wizard/lib/financial-core.d.ts +6 -0
- package/dist/wizard/lib/financial-core.js +5 -0
- package/dist/wizard/lib/financial-vault.d.ts +34 -0
- package/dist/wizard/lib/financial-vault.js +199 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +96 -0
- package/dist/wizard/lib/gap-analysis.d.ts +37 -0
- package/dist/wizard/lib/gap-analysis.js +218 -0
- package/dist/wizard/lib/github.d.ts +22 -0
- package/dist/wizard/lib/github.js +261 -0
- package/dist/wizard/lib/headless-deploy.d.ts +14 -0
- package/dist/wizard/lib/headless-deploy.js +452 -0
- package/dist/wizard/lib/health-monitor.d.ts +15 -0
- package/dist/wizard/lib/health-monitor.js +91 -0
- package/dist/wizard/lib/health-poller.d.ts +9 -0
- package/dist/wizard/lib/health-poller.js +123 -0
- package/dist/wizard/lib/heartbeat.d.ts +15 -0
- package/dist/wizard/lib/heartbeat.js +827 -0
- package/dist/wizard/lib/http-helpers.d.ts +9 -0
- package/dist/wizard/lib/http-helpers.js +24 -0
- package/dist/wizard/lib/image-gen.d.ts +56 -0
- package/dist/wizard/lib/image-gen.js +159 -0
- package/dist/wizard/lib/instance-sizing.d.ts +26 -0
- package/dist/wizard/lib/instance-sizing.js +51 -0
- package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
- package/dist/wizard/lib/kongo/analytics.js +179 -0
- package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
- package/dist/wizard/lib/kongo/campaigns.js +91 -0
- package/dist/wizard/lib/kongo/client.d.ts +58 -0
- package/dist/wizard/lib/kongo/client.js +221 -0
- package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
- package/dist/wizard/lib/kongo/jobs.js +122 -0
- package/dist/wizard/lib/kongo/pages.d.ts +60 -0
- package/dist/wizard/lib/kongo/pages.js +150 -0
- package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
- package/dist/wizard/lib/kongo/provisioner.js +116 -0
- package/dist/wizard/lib/kongo/seed.d.ts +49 -0
- package/dist/wizard/lib/kongo/seed.js +237 -0
- package/dist/wizard/lib/kongo/types.d.ts +323 -0
- package/dist/wizard/lib/kongo/types.js +11 -0
- package/dist/wizard/lib/kongo/variants.d.ts +57 -0
- package/dist/wizard/lib/kongo/variants.js +88 -0
- package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
- package/dist/wizard/lib/kongo/webhooks.js +112 -0
- package/dist/wizard/lib/marker.d.ts +28 -0
- package/dist/wizard/lib/marker.js +79 -0
- package/dist/wizard/lib/migrator.d.ts +35 -0
- package/dist/wizard/lib/migrator.js +190 -0
- package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
- package/dist/wizard/lib/natural-language-deploy.js +186 -0
- package/dist/wizard/lib/network.d.ts +22 -0
- package/dist/wizard/lib/network.js +72 -0
- package/dist/wizard/lib/oauth-core.d.ts +6 -0
- package/dist/wizard/lib/oauth-core.js +5 -0
- package/dist/wizard/lib/open-browser.d.ts +1 -0
- package/dist/wizard/lib/open-browser.js +26 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
- package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
- package/dist/wizard/lib/patterns/daemon-process.js +271 -0
- package/dist/wizard/lib/patterns/financial-transaction.d.ts +161 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +132 -0
- package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
- package/dist/wizard/lib/patterns/funding-plan.js +200 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
- package/dist/wizard/lib/prd-validator.d.ts +39 -0
- package/dist/wizard/lib/prd-validator.js +137 -0
- package/dist/wizard/lib/project-init.d.ts +24 -0
- package/dist/wizard/lib/project-init.js +193 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -0
- package/dist/wizard/lib/provision-manifest.d.ts +44 -0
- package/dist/wizard/lib/provision-manifest.js +164 -0
- package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
- package/dist/wizard/lib/provisioner-registry.js +34 -0
- package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +643 -0
- package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
- package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
- package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
- package/dist/wizard/lib/provisioners/docker.js +75 -0
- package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
- package/dist/wizard/lib/provisioners/http-client.js +79 -0
- package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +413 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
- package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
- package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
- package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
- package/dist/wizard/lib/provisioners/static-s3.js +235 -0
- package/dist/wizard/lib/provisioners/types.d.ts +40 -0
- package/dist/wizard/lib/provisioners/types.js +4 -0
- package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
- package/dist/wizard/lib/provisioners/vercel.js +287 -0
- package/dist/wizard/lib/pty-manager.d.ts +42 -0
- package/dist/wizard/lib/pty-manager.js +231 -0
- package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
- package/dist/wizard/lib/rate-limiter-core.js +5 -0
- package/dist/wizard/lib/reconciliation.d.ts +43 -0
- package/dist/wizard/lib/reconciliation.js +173 -0
- package/dist/wizard/lib/revenue-types.d.ts +5 -0
- package/dist/wizard/lib/revenue-types.js +1 -0
- package/dist/wizard/lib/route-optimizer.d.ts +28 -0
- package/dist/wizard/lib/route-optimizer.js +93 -0
- package/dist/wizard/lib/s3-deploy.d.ts +19 -0
- package/dist/wizard/lib/s3-deploy.js +156 -0
- package/dist/wizard/lib/safety-tiers.d.ts +76 -0
- package/dist/wizard/lib/safety-tiers.js +134 -0
- package/dist/wizard/lib/sentry-generator.d.ts +15 -0
- package/dist/wizard/lib/sentry-generator.js +116 -0
- package/dist/wizard/lib/server-config.d.ts +13 -0
- package/dist/wizard/lib/server-config.js +23 -0
- package/dist/wizard/lib/service-install.d.ts +18 -0
- package/dist/wizard/lib/service-install.js +182 -0
- package/dist/wizard/lib/site-scanner.d.ts +80 -0
- package/dist/wizard/lib/site-scanner.js +262 -0
- package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
- package/dist/wizard/lib/ssh-deploy.js +225 -0
- package/dist/wizard/lib/templates.d.ts +24 -0
- package/dist/wizard/lib/templates.js +219 -0
- package/dist/wizard/lib/totp.d.ts +35 -0
- package/dist/wizard/lib/totp.js +276 -0
- package/dist/wizard/lib/tower-auth.d.ts +43 -0
- package/dist/wizard/lib/tower-auth.js +352 -0
- package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
- package/dist/wizard/lib/tower-rate-limit.js +61 -0
- package/dist/wizard/lib/tower-session.d.ts +28 -0
- package/dist/wizard/lib/tower-session.js +119 -0
- package/dist/wizard/lib/treasury-backup.d.ts +23 -0
- package/dist/wizard/lib/treasury-backup.js +126 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
- package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +190 -0
- package/dist/wizard/lib/user-manager.d.ts +39 -0
- package/dist/wizard/lib/user-manager.js +182 -0
- package/dist/wizard/lib/vault.d.ts +26 -0
- package/dist/wizard/lib/vault.js +161 -0
- package/dist/wizard/router.d.ts +5 -0
- package/dist/wizard/router.js +15 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +436 -0
- package/package.json +59 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker-compose.yml template generator.
|
|
3
|
+
*/
|
|
4
|
+
export function generateDockerCompose(opts) {
|
|
5
|
+
const services = [];
|
|
6
|
+
const volumes = [];
|
|
7
|
+
const envVars = [];
|
|
8
|
+
// App service
|
|
9
|
+
const appPort = opts.framework === 'django' ? '8000' : '3000';
|
|
10
|
+
const depends = [];
|
|
11
|
+
if (opts.database === 'postgres' || opts.database === 'mysql')
|
|
12
|
+
depends.push('db');
|
|
13
|
+
if (opts.cache === 'redis')
|
|
14
|
+
depends.push('redis');
|
|
15
|
+
let appService = ` app:
|
|
16
|
+
build: .
|
|
17
|
+
ports:
|
|
18
|
+
- "\${PORT:-${appPort}}:${appPort}"
|
|
19
|
+
env_file:
|
|
20
|
+
- .env
|
|
21
|
+
healthcheck:
|
|
22
|
+
test: ["CMD-SHELL", "wget --spider -q http://localhost:${appPort}/ || exit 1"]
|
|
23
|
+
interval: 10s
|
|
24
|
+
timeout: 5s
|
|
25
|
+
retries: 3
|
|
26
|
+
start_period: 15s
|
|
27
|
+
restart: unless-stopped`;
|
|
28
|
+
if (depends.length > 0) {
|
|
29
|
+
appService += `\n depends_on:\n${depends.map((d) => ` ${d}:\n condition: service_healthy`).join('\n')}`;
|
|
30
|
+
}
|
|
31
|
+
services.push(appService);
|
|
32
|
+
// Database service
|
|
33
|
+
if (opts.database === 'postgres') {
|
|
34
|
+
envVars.push('DATABASE_URL=postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@db:5432/${DB_NAME:-app}');
|
|
35
|
+
services.push(` db:
|
|
36
|
+
image: postgres:16-alpine
|
|
37
|
+
environment:
|
|
38
|
+
POSTGRES_USER: \${DB_USER:-postgres}
|
|
39
|
+
POSTGRES_PASSWORD: \${DB_PASSWORD:-postgres}
|
|
40
|
+
POSTGRES_DB: \${DB_NAME:-app}
|
|
41
|
+
expose:
|
|
42
|
+
- "5432"
|
|
43
|
+
volumes:
|
|
44
|
+
- db_data:/var/lib/postgresql/data
|
|
45
|
+
healthcheck:
|
|
46
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
47
|
+
interval: 5s
|
|
48
|
+
timeout: 3s
|
|
49
|
+
retries: 5
|
|
50
|
+
restart: unless-stopped`);
|
|
51
|
+
volumes.push(' db_data:');
|
|
52
|
+
}
|
|
53
|
+
if (opts.database === 'mysql') {
|
|
54
|
+
envVars.push('DATABASE_URL=mysql://root:${DB_PASSWORD:-mysql}@db:3306/${DB_NAME:-app}');
|
|
55
|
+
services.push(` db:
|
|
56
|
+
image: mysql:8.0
|
|
57
|
+
environment:
|
|
58
|
+
MYSQL_ROOT_PASSWORD: \${DB_PASSWORD:-mysql}
|
|
59
|
+
MYSQL_DATABASE: \${DB_NAME:-app}
|
|
60
|
+
expose:
|
|
61
|
+
- "3306"
|
|
62
|
+
volumes:
|
|
63
|
+
- db_data:/var/lib/mysql
|
|
64
|
+
healthcheck:
|
|
65
|
+
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
66
|
+
interval: 5s
|
|
67
|
+
timeout: 3s
|
|
68
|
+
retries: 5
|
|
69
|
+
restart: unless-stopped`);
|
|
70
|
+
volumes.push(' db_data:');
|
|
71
|
+
}
|
|
72
|
+
// Cache service
|
|
73
|
+
if (opts.cache === 'redis') {
|
|
74
|
+
envVars.push('REDIS_URL=redis://redis:6379');
|
|
75
|
+
services.push(` redis:
|
|
76
|
+
image: redis:7-alpine
|
|
77
|
+
expose:
|
|
78
|
+
- "6379"
|
|
79
|
+
healthcheck:
|
|
80
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
81
|
+
interval: 5s
|
|
82
|
+
timeout: 3s
|
|
83
|
+
retries: 5
|
|
84
|
+
restart: unless-stopped`);
|
|
85
|
+
}
|
|
86
|
+
let compose = `services:\n${services.join('\n\n')}\n`;
|
|
87
|
+
if (volumes.length > 0) {
|
|
88
|
+
compose += `\nvolumes:\n${volumes.join('\n')}\n`;
|
|
89
|
+
}
|
|
90
|
+
return compose;
|
|
91
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dockerfile template generator — multi-stage builds per framework.
|
|
3
|
+
*/
|
|
4
|
+
export function generateDockerfile(framework) {
|
|
5
|
+
switch (framework) {
|
|
6
|
+
case 'next.js':
|
|
7
|
+
return nextjsDockerfile();
|
|
8
|
+
case 'express':
|
|
9
|
+
return expressDockerfile();
|
|
10
|
+
case 'django':
|
|
11
|
+
return djangoDockerfile();
|
|
12
|
+
case 'rails':
|
|
13
|
+
return railsDockerfile();
|
|
14
|
+
default:
|
|
15
|
+
return nodeDockerfile();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function nextjsDockerfile() {
|
|
19
|
+
return `# Stage 1: Dependencies
|
|
20
|
+
FROM node:20-alpine AS deps
|
|
21
|
+
WORKDIR /app
|
|
22
|
+
COPY package.json package-lock.json* ./
|
|
23
|
+
RUN npm ci --ignore-scripts
|
|
24
|
+
|
|
25
|
+
# Stage 2: Build
|
|
26
|
+
FROM node:20-alpine AS builder
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
29
|
+
COPY . .
|
|
30
|
+
RUN npm run build
|
|
31
|
+
|
|
32
|
+
# Stage 3: Production
|
|
33
|
+
FROM node:20-alpine AS runner
|
|
34
|
+
WORKDIR /app
|
|
35
|
+
ENV NODE_ENV=production
|
|
36
|
+
|
|
37
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
38
|
+
RUN adduser --system --uid 1001 nextjs
|
|
39
|
+
|
|
40
|
+
COPY --from=builder /app/public ./public
|
|
41
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
42
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
43
|
+
|
|
44
|
+
USER nextjs
|
|
45
|
+
EXPOSE 3000
|
|
46
|
+
ENV PORT=3000
|
|
47
|
+
ENV HOSTNAME="0.0.0.0"
|
|
48
|
+
|
|
49
|
+
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
|
50
|
+
CMD ["sh", "-c", "wget --spider -q http://localhost:3000/ || exit 1"]
|
|
51
|
+
|
|
52
|
+
CMD ["node", "server.js"]
|
|
53
|
+
`;
|
|
54
|
+
}
|
|
55
|
+
function expressDockerfile() {
|
|
56
|
+
return `# Stage 1: Build
|
|
57
|
+
FROM node:20-alpine AS builder
|
|
58
|
+
WORKDIR /app
|
|
59
|
+
COPY package.json package-lock.json* ./
|
|
60
|
+
RUN npm ci --ignore-scripts
|
|
61
|
+
COPY . .
|
|
62
|
+
RUN npm run build
|
|
63
|
+
|
|
64
|
+
# Stage 2: Production
|
|
65
|
+
FROM node:20-alpine
|
|
66
|
+
WORKDIR /app
|
|
67
|
+
ENV NODE_ENV=production
|
|
68
|
+
|
|
69
|
+
RUN addgroup --system --gid 1001 appgroup
|
|
70
|
+
RUN adduser --system --uid 1001 appuser
|
|
71
|
+
|
|
72
|
+
COPY --from=builder /app/package.json ./
|
|
73
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
74
|
+
COPY --from=builder /app/dist ./dist
|
|
75
|
+
|
|
76
|
+
USER appuser
|
|
77
|
+
EXPOSE 3000
|
|
78
|
+
|
|
79
|
+
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
|
80
|
+
CMD ["sh", "-c", "wget --spider -q http://localhost:3000/ || exit 1"]
|
|
81
|
+
|
|
82
|
+
CMD ["node", "dist/index.js"]
|
|
83
|
+
`;
|
|
84
|
+
}
|
|
85
|
+
function djangoDockerfile() {
|
|
86
|
+
return `FROM python:3.12-slim
|
|
87
|
+
|
|
88
|
+
WORKDIR /app
|
|
89
|
+
|
|
90
|
+
RUN addgroup --system --gid 1001 appgroup && \\
|
|
91
|
+
adduser --system --uid 1001 --gid 1001 appuser
|
|
92
|
+
|
|
93
|
+
COPY requirements.txt ./
|
|
94
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
95
|
+
|
|
96
|
+
COPY . .
|
|
97
|
+
|
|
98
|
+
RUN python manage.py collectstatic --noinput
|
|
99
|
+
|
|
100
|
+
USER appuser
|
|
101
|
+
EXPOSE 8000
|
|
102
|
+
|
|
103
|
+
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
|
104
|
+
CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/')"]
|
|
105
|
+
|
|
106
|
+
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "config.wsgi:application"]
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
function railsDockerfile() {
|
|
110
|
+
return `FROM ruby:3.3-slim
|
|
111
|
+
|
|
112
|
+
WORKDIR /app
|
|
113
|
+
|
|
114
|
+
RUN apt-get update -qq && \\
|
|
115
|
+
apt-get install --no-install-recommends -y build-essential libpq-dev && \\
|
|
116
|
+
rm -rf /var/lib/apt/lists/*
|
|
117
|
+
|
|
118
|
+
COPY Gemfile Gemfile.lock ./
|
|
119
|
+
RUN bundle install --without development test
|
|
120
|
+
|
|
121
|
+
COPY . .
|
|
122
|
+
|
|
123
|
+
RUN bundle exec rails assets:precompile
|
|
124
|
+
|
|
125
|
+
RUN addgroup --system --gid 1001 appgroup && \\
|
|
126
|
+
adduser --system --uid 1001 --gid 1001 appuser && \\
|
|
127
|
+
chown -R appuser:appgroup /app
|
|
128
|
+
|
|
129
|
+
USER appuser
|
|
130
|
+
EXPOSE 3000
|
|
131
|
+
|
|
132
|
+
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
|
133
|
+
CMD ["sh", "-c", "wget --spider -q http://localhost:3000/ || exit 1"]
|
|
134
|
+
|
|
135
|
+
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
function nodeDockerfile() {
|
|
139
|
+
return `# Stage 1: Build
|
|
140
|
+
FROM node:20-alpine AS builder
|
|
141
|
+
WORKDIR /app
|
|
142
|
+
COPY package.json package-lock.json* ./
|
|
143
|
+
RUN npm ci --ignore-scripts
|
|
144
|
+
COPY . .
|
|
145
|
+
RUN npm run build
|
|
146
|
+
|
|
147
|
+
# Stage 2: Production
|
|
148
|
+
FROM node:20-alpine
|
|
149
|
+
WORKDIR /app
|
|
150
|
+
ENV NODE_ENV=production
|
|
151
|
+
|
|
152
|
+
RUN addgroup --system --gid 1001 appgroup
|
|
153
|
+
RUN adduser --system --uid 1001 appuser
|
|
154
|
+
|
|
155
|
+
COPY --from=builder /app/package.json ./
|
|
156
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
157
|
+
COPY --from=builder /app/dist ./dist
|
|
158
|
+
|
|
159
|
+
USER appuser
|
|
160
|
+
EXPOSE 3000
|
|
161
|
+
|
|
162
|
+
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \\
|
|
163
|
+
CMD ["sh", "-c", "wget --spider -q http://localhost:3000/ || exit 1"]
|
|
164
|
+
|
|
165
|
+
CMD ["node", "dist/index.js"]
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
export function generateDockerignore() {
|
|
169
|
+
return `node_modules
|
|
170
|
+
.git
|
|
171
|
+
.gitignore
|
|
172
|
+
.env
|
|
173
|
+
.env.*
|
|
174
|
+
*.md
|
|
175
|
+
logs/
|
|
176
|
+
docs/
|
|
177
|
+
.claude/
|
|
178
|
+
.next/cache
|
|
179
|
+
dist/
|
|
180
|
+
coverage/
|
|
181
|
+
.vscode/
|
|
182
|
+
.idea/
|
|
183
|
+
*.log
|
|
184
|
+
`;
|
|
185
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: ecosystem.config.js — PM2 process manager configuration.
|
|
3
|
+
* Written to projectDir/ecosystem.config.js
|
|
4
|
+
*/
|
|
5
|
+
interface EcosystemOptions {
|
|
6
|
+
projectName: string;
|
|
7
|
+
framework: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateEcosystemConfig(opts: EcosystemOptions): string;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: ecosystem.config.js — PM2 process manager configuration.
|
|
3
|
+
* Written to projectDir/ecosystem.config.js
|
|
4
|
+
*/
|
|
5
|
+
export function generateEcosystemConfig(opts) {
|
|
6
|
+
const isNextjs = opts.framework === 'next.js';
|
|
7
|
+
const script = isNextjs ? 'node_modules/.bin/next' : 'dist/index.js';
|
|
8
|
+
const args = isNextjs ? 'start' : '';
|
|
9
|
+
const instances = isNextjs ? '2' : 'max';
|
|
10
|
+
return `// ecosystem.config.js — PM2 configuration
|
|
11
|
+
// Generated by VoidForge
|
|
12
|
+
module.exports = {
|
|
13
|
+
apps: [
|
|
14
|
+
{
|
|
15
|
+
name: ${JSON.stringify(opts.projectName)},
|
|
16
|
+
script: '${script}',${args ? `\n args: '${args}',` : ''}
|
|
17
|
+
instances: '${instances}',
|
|
18
|
+
exec_mode: 'cluster',
|
|
19
|
+
env_production: {
|
|
20
|
+
NODE_ENV: 'production',
|
|
21
|
+
PORT: 3000,
|
|
22
|
+
},
|
|
23
|
+
max_memory_restart: '512M',
|
|
24
|
+
max_restarts: 10,
|
|
25
|
+
min_uptime: '5s',
|
|
26
|
+
listen_timeout: 10000,
|
|
27
|
+
kill_timeout: 5000,
|
|
28
|
+
error_file: '/opt/app/logs/error.log',
|
|
29
|
+
out_file: '/opt/app/logs/out.log',
|
|
30
|
+
merge_logs: true,
|
|
31
|
+
time: true,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: provision.sh — idempotent server setup for VPS.
|
|
3
|
+
* Includes security hardening (fail2ban, SSH, firewall), swap, log rotation.
|
|
4
|
+
* Written to projectDir/infra/provision.sh
|
|
5
|
+
*/
|
|
6
|
+
interface ProvisionScriptOptions {
|
|
7
|
+
framework: string;
|
|
8
|
+
database: string;
|
|
9
|
+
cache: string;
|
|
10
|
+
instanceType?: string;
|
|
11
|
+
extensions?: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare function generateProvisionScript(opts: ProvisionScriptOptions): string;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: provision.sh — idempotent server setup for VPS.
|
|
3
|
+
* Includes security hardening (fail2ban, SSH, firewall), swap, log rotation.
|
|
4
|
+
* Written to projectDir/infra/provision.sh
|
|
5
|
+
*/
|
|
6
|
+
// QA-001/SEC-009: Allowlist of safe PostgreSQL extensions — prevent SQL injection via extension names
|
|
7
|
+
const ALLOWED_EXTENSIONS = ['postgis', 'pg_trgm', 'uuid-ossp', 'pgcrypto', 'citext', 'hstore', 'ltree', 'cube', 'earthdistance', 'unaccent', 'vector', 'pg_stat_statements', 'tablefunc', 'btree_gist', 'btree_gin', 'fuzzystrmatch'];
|
|
8
|
+
/** Generate PostgreSQL extension install commands if extensions are specified. */
|
|
9
|
+
function generateExtensionBlock(opts) {
|
|
10
|
+
if (!opts.extensions || opts.extensions.length === 0 || opts.database !== 'postgres')
|
|
11
|
+
return '';
|
|
12
|
+
// Filter to only allowed extensions
|
|
13
|
+
const safeExtensions = opts.extensions.filter(ext => ALLOWED_EXTENSIONS.includes(ext.toLowerCase().trim()));
|
|
14
|
+
if (safeExtensions.length === 0)
|
|
15
|
+
return '';
|
|
16
|
+
const lines = [
|
|
17
|
+
'',
|
|
18
|
+
'# ==========================================',
|
|
19
|
+
'# PostgreSQL Extensions',
|
|
20
|
+
'# ==========================================',
|
|
21
|
+
];
|
|
22
|
+
for (const ext of safeExtensions) {
|
|
23
|
+
const extLower = ext.toLowerCase().trim();
|
|
24
|
+
if (extLower === 'postgis') {
|
|
25
|
+
lines.push('echo "Installing PostGIS..."');
|
|
26
|
+
lines.push('dnf install -y -q postgis34_16 || apt-get install -y -q postgresql-16-postgis-3 2>/dev/null || true');
|
|
27
|
+
}
|
|
28
|
+
else if (extLower === 'pg_trgm') {
|
|
29
|
+
lines.push('echo "Installing pg_trgm..."');
|
|
30
|
+
lines.push('# pg_trgm is included in postgresql-contrib (usually pre-installed)');
|
|
31
|
+
lines.push('dnf install -y -q postgresql16-contrib 2>/dev/null || apt-get install -y -q postgresql-contrib 2>/dev/null || true');
|
|
32
|
+
}
|
|
33
|
+
// CREATE EXTENSION is idempotent
|
|
34
|
+
lines.push(`sudo -u postgres psql -d "$\{DB_NAME:-app}" -c "CREATE EXTENSION IF NOT EXISTS ${extLower};" 2>/dev/null || true`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
export function generateProvisionScript(opts) {
|
|
39
|
+
const nodeSetup = ['next.js', 'express'].includes(opts.framework) || !opts.framework;
|
|
40
|
+
const pythonSetup = opts.framework === 'django';
|
|
41
|
+
const rubySetup = opts.framework === 'rails';
|
|
42
|
+
let runtimeInstall = '';
|
|
43
|
+
if (nodeSetup) {
|
|
44
|
+
runtimeInstall = `
|
|
45
|
+
# Install Node.js 20.x
|
|
46
|
+
if ! command -v node &>/dev/null; then
|
|
47
|
+
echo "Installing Node.js..."
|
|
48
|
+
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
|
|
49
|
+
dnf install -y nodejs
|
|
50
|
+
fi
|
|
51
|
+
echo "Node.js $(node --version)"
|
|
52
|
+
|
|
53
|
+
# Install PM2 globally
|
|
54
|
+
if ! command -v pm2 &>/dev/null; then
|
|
55
|
+
npm install -g pm2
|
|
56
|
+
fi
|
|
57
|
+
echo "PM2 $(pm2 --version)"
|
|
58
|
+
|
|
59
|
+
# Set up PM2 to start on boot
|
|
60
|
+
pm2 startup systemd -u appuser --hp /opt/app 2>/dev/null || true`;
|
|
61
|
+
}
|
|
62
|
+
else if (pythonSetup) {
|
|
63
|
+
runtimeInstall = `
|
|
64
|
+
# Install Python 3.12
|
|
65
|
+
if ! command -v python3.12 &>/dev/null; then
|
|
66
|
+
echo "Installing Python 3.12..."
|
|
67
|
+
dnf install -y python3.12 python3.12-pip
|
|
68
|
+
fi
|
|
69
|
+
echo "Python $(python3.12 --version)"
|
|
70
|
+
|
|
71
|
+
# Install gunicorn + supervisor
|
|
72
|
+
pip3.12 install --quiet gunicorn supervisor`;
|
|
73
|
+
}
|
|
74
|
+
else if (rubySetup) {
|
|
75
|
+
runtimeInstall = `
|
|
76
|
+
# Install Ruby
|
|
77
|
+
if ! command -v ruby &>/dev/null; then
|
|
78
|
+
echo "Installing Ruby..."
|
|
79
|
+
dnf install -y ruby ruby-devel
|
|
80
|
+
fi
|
|
81
|
+
echo "Ruby $(ruby --version)"
|
|
82
|
+
|
|
83
|
+
# Install bundler
|
|
84
|
+
gem install bundler --no-document`;
|
|
85
|
+
}
|
|
86
|
+
return `#!/usr/bin/env bash
|
|
87
|
+
# provision.sh — Idempotent VPS setup with security hardening
|
|
88
|
+
# Generated by VoidForge. Safe to re-run.
|
|
89
|
+
set -euo pipefail
|
|
90
|
+
|
|
91
|
+
echo "=== VoidForge VPS Provisioning ==="
|
|
92
|
+
|
|
93
|
+
# Update system
|
|
94
|
+
echo "Updating packages..."
|
|
95
|
+
dnf update -y -q
|
|
96
|
+
|
|
97
|
+
# Install essentials
|
|
98
|
+
dnf install -y -q git curl wget tar unzip
|
|
99
|
+
${runtimeInstall}
|
|
100
|
+
|
|
101
|
+
# Install Caddy (reverse proxy + auto HTTPS)
|
|
102
|
+
if ! command -v caddy &>/dev/null; then
|
|
103
|
+
echo "Installing Caddy..."
|
|
104
|
+
dnf install -y 'dnf-command(copr)'
|
|
105
|
+
dnf copr enable -y @caddy/caddy
|
|
106
|
+
dnf install -y caddy
|
|
107
|
+
systemctl enable caddy
|
|
108
|
+
fi
|
|
109
|
+
echo "Caddy $(caddy version)"
|
|
110
|
+
|
|
111
|
+
# ==========================================
|
|
112
|
+
# Security Hardening
|
|
113
|
+
# ==========================================
|
|
114
|
+
|
|
115
|
+
# Install and configure fail2ban
|
|
116
|
+
echo "Configuring fail2ban..."
|
|
117
|
+
dnf install -y -q fail2ban
|
|
118
|
+
cat > /etc/fail2ban/jail.local << 'JAIL'
|
|
119
|
+
[sshd]
|
|
120
|
+
enabled = true
|
|
121
|
+
port = ssh
|
|
122
|
+
filter = sshd
|
|
123
|
+
maxretry = 5
|
|
124
|
+
bantime = 3600
|
|
125
|
+
findtime = 600
|
|
126
|
+
JAIL
|
|
127
|
+
systemctl enable --now fail2ban
|
|
128
|
+
|
|
129
|
+
# Harden SSH — disable root login and password auth
|
|
130
|
+
echo "Hardening SSH..."
|
|
131
|
+
sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
|
|
132
|
+
sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
|
133
|
+
systemctl reload sshd
|
|
134
|
+
|
|
135
|
+
# Enable unattended security updates
|
|
136
|
+
echo "Enabling automatic security updates..."
|
|
137
|
+
dnf install -y -q dnf-automatic
|
|
138
|
+
sed -i 's/^apply_updates.*/apply_updates = yes/' /etc/dnf/automatic.conf
|
|
139
|
+
systemctl enable --now dnf-automatic-install.timer
|
|
140
|
+
|
|
141
|
+
# ==========================================
|
|
142
|
+
# Application Setup
|
|
143
|
+
# ==========================================
|
|
144
|
+
|
|
145
|
+
# Create app directories (release-directory structure)
|
|
146
|
+
APP_DIR="/opt/app"
|
|
147
|
+
mkdir -p "$APP_DIR/releases" "$APP_DIR/logs"
|
|
148
|
+
|
|
149
|
+
# Create app user if not exists
|
|
150
|
+
if ! id -u appuser &>/dev/null; then
|
|
151
|
+
useradd --system --home-dir "$APP_DIR" --shell /bin/bash appuser
|
|
152
|
+
fi
|
|
153
|
+
chown -R appuser:appuser "$APP_DIR"
|
|
154
|
+
|
|
155
|
+
# ==========================================
|
|
156
|
+
# Firewall — lock down then open
|
|
157
|
+
# ==========================================
|
|
158
|
+
echo "Configuring firewall..."
|
|
159
|
+
if command -v firewall-cmd &>/dev/null; then
|
|
160
|
+
firewall-cmd --set-default-zone=drop 2>/dev/null || true
|
|
161
|
+
firewall-cmd --permanent --add-service=ssh 2>/dev/null || true
|
|
162
|
+
firewall-cmd --permanent --add-service=http 2>/dev/null || true
|
|
163
|
+
firewall-cmd --permanent --add-service=https 2>/dev/null || true
|
|
164
|
+
firewall-cmd --reload 2>/dev/null || true
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# ==========================================
|
|
168
|
+
# Swap (prevents OOM during builds)
|
|
169
|
+
# ==========================================
|
|
170
|
+
${opts.instanceType === 't3.large' ? '# Swap skipped — t3.large has 8 GiB RAM' : `if [ ! -f /swapfile ]; then
|
|
171
|
+
echo "Setting up ${opts.instanceType === 't3.medium' ? '1GB' : '2GB'} swap..."
|
|
172
|
+
fallocate -l ${opts.instanceType === 't3.medium' ? '1G' : '2G'} /swapfile
|
|
173
|
+
chmod 600 /swapfile
|
|
174
|
+
mkswap /swapfile
|
|
175
|
+
swapon /swapfile
|
|
176
|
+
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
|
177
|
+
fi`}
|
|
178
|
+
|
|
179
|
+
# ==========================================
|
|
180
|
+
# Log Rotation
|
|
181
|
+
# ==========================================
|
|
182
|
+
cat > /etc/logrotate.d/voidforge << 'LOGROTATE'
|
|
183
|
+
/opt/app/logs/*.log {
|
|
184
|
+
daily
|
|
185
|
+
rotate 14
|
|
186
|
+
compress
|
|
187
|
+
delaycompress
|
|
188
|
+
missingok
|
|
189
|
+
notifempty
|
|
190
|
+
copytruncate
|
|
191
|
+
}
|
|
192
|
+
LOGROTATE
|
|
193
|
+
|
|
194
|
+
${generateExtensionBlock(opts)}
|
|
195
|
+
echo ""
|
|
196
|
+
echo "=== Provisioning complete ==="
|
|
197
|
+
echo "App directory: $APP_DIR/releases/ (symlinked via $APP_DIR/current)"
|
|
198
|
+
echo "App user: appuser"
|
|
199
|
+
echo "Security: fail2ban active, SSH hardened, firewall locked down"
|
|
200
|
+
echo "Next: run deploy.sh to deploy your app"
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: rollback.sh — swap to previous release directory.
|
|
3
|
+
* Compatible with deploy.sh's release-directory strategy.
|
|
4
|
+
* Written to projectDir/infra/rollback.sh
|
|
5
|
+
*/
|
|
6
|
+
interface RollbackScriptOptions {
|
|
7
|
+
framework: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateRollbackScript(opts: RollbackScriptOptions): string;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template: rollback.sh — swap to previous release directory.
|
|
3
|
+
* Compatible with deploy.sh's release-directory strategy.
|
|
4
|
+
* Written to projectDir/infra/rollback.sh
|
|
5
|
+
*/
|
|
6
|
+
export function generateRollbackScript(opts) {
|
|
7
|
+
const isNode = ['next.js', 'express'].includes(opts.framework) || !opts.framework;
|
|
8
|
+
const isDjango = opts.framework === 'django';
|
|
9
|
+
let restartCommands;
|
|
10
|
+
if (isNode) {
|
|
11
|
+
restartCommands = 'pm2 startOrRestart /opt/app/current/ecosystem.config.js --env production && pm2 save';
|
|
12
|
+
}
|
|
13
|
+
else if (isDjango) {
|
|
14
|
+
restartCommands = 'python3.12 manage.py migrate --noinput && supervisorctl restart app';
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
restartCommands = 'RAILS_ENV=production bundle exec rails db:migrate && touch tmp/restart.txt';
|
|
18
|
+
}
|
|
19
|
+
return `#!/usr/bin/env bash
|
|
20
|
+
# rollback.sh — Roll back to the previous release
|
|
21
|
+
# Generated by VoidForge. Uses release-directory strategy.
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
# Load environment
|
|
25
|
+
if [ -f .env ]; then
|
|
26
|
+
set -a
|
|
27
|
+
source .env
|
|
28
|
+
set +a
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
SSH_HOST="\${SSH_HOST:?Set SSH_HOST in .env}"
|
|
32
|
+
SSH_USER="\${SSH_USER:-ec2-user}"
|
|
33
|
+
SSH_KEY="\${SSH_KEY_PATH:-.ssh/deploy-key.pem}"
|
|
34
|
+
RELEASES_DIR="/opt/app/releases"
|
|
35
|
+
CURRENT_LINK="/opt/app/current"
|
|
36
|
+
|
|
37
|
+
SSH_OPTS="-i $SSH_KEY -o StrictHostKeyChecking=accept-new"
|
|
38
|
+
|
|
39
|
+
echo "=== Rolling back on $SSH_HOST ==="
|
|
40
|
+
|
|
41
|
+
# Find current and previous releases
|
|
42
|
+
CURRENT="$(ssh $SSH_OPTS $SSH_USER@$SSH_HOST "readlink $CURRENT_LINK 2>/dev/null || echo ''")"
|
|
43
|
+
RELEASES="$(ssh $SSH_OPTS $SSH_USER@$SSH_HOST "ls -1d $RELEASES_DIR/*/ 2>/dev/null | sort")"
|
|
44
|
+
PREVIOUS="$(echo "$RELEASES" | grep -B1 "$(basename "$CURRENT")" | head -1)"
|
|
45
|
+
|
|
46
|
+
if [ -z "$PREVIOUS" ] || [ "$PREVIOUS" = "$CURRENT" ]; then
|
|
47
|
+
echo "No previous release to roll back to!"
|
|
48
|
+
echo "Available releases:"
|
|
49
|
+
ssh $SSH_OPTS $SSH_USER@$SSH_HOST "ls -1d $RELEASES_DIR/*/ 2>/dev/null"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
echo "Current: $(basename "$CURRENT")"
|
|
54
|
+
echo "Rolling back to: $(basename "$PREVIOUS")"
|
|
55
|
+
|
|
56
|
+
# Swap symlink
|
|
57
|
+
ssh $SSH_OPTS $SSH_USER@$SSH_HOST "ln -sfn $PREVIOUS $CURRENT_LINK"
|
|
58
|
+
|
|
59
|
+
# Restart
|
|
60
|
+
ssh $SSH_OPTS $SSH_USER@$SSH_HOST "cd $CURRENT_LINK && ${restartCommands}"
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
echo "=== Rollback complete ==="
|
|
64
|
+
echo "Now running: $(basename "$PREVIOUS")"
|
|
65
|
+
echo "Run deploy.sh to re-deploy the latest code."
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-Deploy Provisioner — deploys VoidForge itself to a remote VPS.
|
|
3
|
+
*
|
|
4
|
+
* Usage: npx voidforge deploy --self
|
|
5
|
+
*
|
|
6
|
+
* Steps:
|
|
7
|
+
* 1. Connect to VPS via SSH (EC2 or manual target)
|
|
8
|
+
* 2. Install: Node.js, Git, PM2, Caddy, Claude Code
|
|
9
|
+
* 3. Clone VoidForge, configure Caddy for HTTPS
|
|
10
|
+
* 4. Create forge-user (non-root PTY execution)
|
|
11
|
+
* 5. Generate initial admin credentials + TOTP secret
|
|
12
|
+
* 6. Start VoidForge as PM2-managed service
|
|
13
|
+
* 7. Report public URL + TOTP QR setup instructions
|
|
14
|
+
*/
|
|
15
|
+
export interface SelfDeployConfig {
|
|
16
|
+
sshHost: string;
|
|
17
|
+
sshUser: string;
|
|
18
|
+
sshKeyPath: string;
|
|
19
|
+
domain: string;
|
|
20
|
+
nodeVersion: string;
|
|
21
|
+
voidforgeRepo: string;
|
|
22
|
+
voidforgeBranch: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SelfDeployResult {
|
|
25
|
+
publicUrl: string;
|
|
26
|
+
adminUsername: string;
|
|
27
|
+
totpSecret: string;
|
|
28
|
+
totpUri: string;
|
|
29
|
+
caddyDomain: string;
|
|
30
|
+
pm2Name: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate the provision script that runs on the remote VPS.
|
|
34
|
+
* This script is piped over SSH — no files need to exist on the remote first.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateProvisionScript(config: SelfDeployConfig): string;
|
|
37
|
+
/**
|
|
38
|
+
* Generate the Caddy config template for manual setup.
|
|
39
|
+
* Used when the user wants to configure Caddy themselves.
|
|
40
|
+
*/
|
|
41
|
+
export declare function generateCaddyTemplate(domain: string): string;
|