Scaffold blackroad-infra: Terraform modules, Docker configs, CI templates
- Terraform environments (production, staging) with R2 backend - Terraform modules: cloudflare-pages, cloudflare-worker, railway-service, digitalocean-droplet - Docker: multi-stage Dockerfiles for core, web, agents, operator + compose - CI templates: node-ci, terraform-ci, docker-ci reusable workflows - Composite actions: brand-compliance, deploy-cloudflare - Operational scripts: bootstrap, health-check, rotate-keys - GitHub Actions: terraform-plan, terraform-apply, docker-build Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @alexa-amundson
|
||||||
15
.github/pull_request_template.md
vendored
Normal file
15
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## Summary
|
||||||
|
<!-- What does this PR change? -->
|
||||||
|
|
||||||
|
## Type
|
||||||
|
- [ ] Terraform module
|
||||||
|
- [ ] Docker config
|
||||||
|
- [ ] CI/CD workflow
|
||||||
|
- [ ] Script
|
||||||
|
- [ ] Documentation
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
- [ ] `terraform validate` passes (if applicable)
|
||||||
|
- [ ] Docker builds successfully (if applicable)
|
||||||
|
- [ ] No secrets committed
|
||||||
|
- [ ] Documentation updated
|
||||||
27
.github/workflows/docker-build.yml
vendored
Normal file
27
.github/workflows/docker-build.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Docker Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths: ['docker/**']
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
paths: ['docker/**']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
service: [core, web, agents, operator]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: docker/setup-buildx-action@v3
|
||||||
|
- uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: docker/${{ matrix.service }}
|
||||||
|
push: false
|
||||||
|
tags: blackroad/${{ matrix.service }}:${{ github.sha }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
31
.github/workflows/terraform-apply.yml
vendored
Normal file
31
.github/workflows/terraform-apply.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Terraform Apply
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths: ['terraform/**']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
apply:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: production
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: terraform/environments/production
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: "1.7"
|
||||||
|
- run: terraform init
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
|
||||||
|
- run: terraform apply -auto-approve
|
||||||
|
env:
|
||||||
|
TF_VAR_cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
TF_VAR_cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
TF_VAR_digitalocean_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
|
||||||
25
.github/workflows/terraform-plan.yml
vendored
Normal file
25
.github/workflows/terraform-plan.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Terraform Plan
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
paths: ['terraform/**']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
plan:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
environment: [staging, production]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: terraform/environments/${{ matrix.environment }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: "1.7"
|
||||||
|
- run: terraform init -backend=false
|
||||||
|
- run: terraform validate
|
||||||
|
- run: terraform fmt -check
|
||||||
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.terraform/
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.backup
|
||||||
|
*.tfvars
|
||||||
|
!terraform.tfvars.example
|
||||||
|
.env
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"semi": false
|
||||||
|
}
|
||||||
18
CLAUDE.md
Normal file
18
CLAUDE.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# CLAUDE.md — blackroad-infra
|
||||||
|
|
||||||
|
Infrastructure-as-Code for BlackRoad OS. Terraform modules, Docker configs, CI templates, and operational scripts.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
- Terraform (Cloudflare, DigitalOcean, Railway modules)
|
||||||
|
- Docker (multi-service compose)
|
||||||
|
- GitHub Actions (reusable workflows and composite actions)
|
||||||
|
|
||||||
|
## Key Directories
|
||||||
|
- `terraform/environments/` — Production and staging configs
|
||||||
|
- `terraform/modules/` — Reusable Terraform modules
|
||||||
|
- `docker/` — Dockerfiles and docker-compose
|
||||||
|
- `ci/` — Reusable workflow templates and composite actions
|
||||||
|
- `scripts/` — Operational shell scripts
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
All files are proprietary to BlackRoad OS, Inc.
|
||||||
6
LICENSE
Normal file
6
LICENSE
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
PROPRIETARY AND CONFIDENTIAL
|
||||||
|
|
||||||
|
This software and related documentation are proprietary to BlackRoad OS, Inc.
|
||||||
|
Unauthorized copying, distribution, or use is strictly prohibited.
|
||||||
44
README.md
44
README.md
@@ -1,2 +1,44 @@
|
|||||||
# blackroad-infra
|
# blackroad-infra
|
||||||
Infrastructure-as-code, CI/CD workflows, deployment configurations, and environment orchestration.
|
|
||||||
|
Infrastructure-as-Code, Docker configs, CI templates, and operational scripts for BlackRoad OS.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform/
|
||||||
|
environments/ # Production and staging configs
|
||||||
|
modules/ # Reusable Terraform modules
|
||||||
|
docker/ # Dockerfiles and docker-compose
|
||||||
|
ci/
|
||||||
|
templates/ # Reusable GitHub Actions workflows
|
||||||
|
actions/ # Composite GitHub Actions
|
||||||
|
scripts/ # Operational shell scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Terraform >= 1.7
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Node.js >= 22
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/bootstrap.sh # Check tooling
|
||||||
|
cd docker && docker compose up # Run all services
|
||||||
|
cd terraform/environments/staging
|
||||||
|
terraform init -backend=false && terraform validate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Terraform Modules
|
||||||
|
|
||||||
|
| Module | Purpose |
|
||||||
|
|--------|---------|
|
||||||
|
| `cloudflare-pages` | Pages project deployment |
|
||||||
|
| `cloudflare-worker` | Worker script + route |
|
||||||
|
| `railway-service` | Railway CLI deployment |
|
||||||
|
| `digitalocean-droplet` | Droplet + firewall |
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
|||||||
29
ci/actions/brand-compliance/action.yml
Normal file
29
ci/actions/brand-compliance/action.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Brand Compliance Check
|
||||||
|
description: Verify CSS and UI files use approved BlackRoad brand colors
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
scan-path:
|
||||||
|
description: Directory to scan
|
||||||
|
default: "."
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Check for forbidden colors
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "Checking brand compliance in ${{ inputs.scan-path }}..."
|
||||||
|
FORBIDDEN=("#FF9D00" "#FF6B00" "#FF0066" "#FF006B" "#D600AA" "#7700FF" "#0066FF")
|
||||||
|
FOUND=0
|
||||||
|
for color in "${FORBIDDEN[@]}"; do
|
||||||
|
if grep -ri "$color" "${{ inputs.scan-path }}" --include="*.css" --include="*.tsx" --include="*.ts" 2>/dev/null; then
|
||||||
|
echo "FORBIDDEN COLOR FOUND: $color"
|
||||||
|
FOUND=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $FOUND -eq 1 ]; then
|
||||||
|
echo "Brand compliance check FAILED"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Brand compliance check PASSED"
|
||||||
30
ci/actions/deploy-cloudflare/action.yml
Normal file
30
ci/actions/deploy-cloudflare/action.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Deploy to Cloudflare Pages
|
||||||
|
description: Build and deploy a project to Cloudflare Pages
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
project-name:
|
||||||
|
description: Cloudflare Pages project name
|
||||||
|
required: true
|
||||||
|
directory:
|
||||||
|
description: Build output directory to deploy
|
||||||
|
required: true
|
||||||
|
api-token:
|
||||||
|
description: Cloudflare API token
|
||||||
|
required: true
|
||||||
|
account-id:
|
||||||
|
description: Cloudflare account ID
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
npx wrangler pages deploy "${{ inputs.directory }}" \
|
||||||
|
--project-name="${{ inputs.project-name }}" \
|
||||||
|
--branch="${GITHUB_REF_NAME}"
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ inputs.api-token }}
|
||||||
|
CLOUDFLARE_ACCOUNT_ID: ${{ inputs.account-id }}
|
||||||
29
ci/templates/docker-ci.yml
Normal file
29
ci/templates/docker-ci.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Docker CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
context:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
image-name:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
secrets:
|
||||||
|
registry-token:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: docker/setup-buildx-action@v3
|
||||||
|
- uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: ${{ inputs.context }}
|
||||||
|
push: false
|
||||||
|
tags: ${{ inputs.image-name }}:${{ github.sha }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
30
ci/templates/node-ci.yml
Normal file
30
ci/templates/node-ci.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Node.js CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
node-version:
|
||||||
|
type: string
|
||||||
|
default: "22"
|
||||||
|
working-directory:
|
||||||
|
type: string
|
||||||
|
default: "."
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ${{ inputs.working-directory }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ inputs.node-version }}
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run lint --if-present
|
||||||
|
- run: npm run typecheck --if-present
|
||||||
|
- run: npm test --if-present
|
||||||
27
ci/templates/terraform-ci.yml
Normal file
27
ci/templates/terraform-ci.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
name: Terraform CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
working-directory:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
terraform-version:
|
||||||
|
type: string
|
||||||
|
default: "1.7"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ${{ inputs.working-directory }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
with:
|
||||||
|
terraform_version: ${{ inputs.terraform-version }}
|
||||||
|
- run: terraform fmt -check -recursive
|
||||||
|
- run: terraform init -backend=false
|
||||||
|
- run: terraform validate
|
||||||
15
docker/agents/Dockerfile
Normal file
15
docker/agents/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/package.json ./
|
||||||
|
EXPOSE 8788
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
15
docker/core/Dockerfile
Normal file
15
docker/core/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/package.json ./
|
||||||
|
EXPOSE 8787
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
63
docker/docker-compose.yml
Normal file
63
docker/docker-compose.yml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
core:
|
||||||
|
build:
|
||||||
|
context: ./core
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8787:8787"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- BLACKROAD_GATEWAY_PORT=8787
|
||||||
|
networks:
|
||||||
|
- blackroad
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: ./web
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- NEXT_PUBLIC_GATEWAY_URL=http://core:8787
|
||||||
|
depends_on:
|
||||||
|
- core
|
||||||
|
networks:
|
||||||
|
- blackroad
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
agents:
|
||||||
|
build:
|
||||||
|
context: ./agents
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8788:8788"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- GATEWAY_URL=http://core:8787
|
||||||
|
depends_on:
|
||||||
|
- core
|
||||||
|
networks:
|
||||||
|
- blackroad
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
operator:
|
||||||
|
build:
|
||||||
|
context: ./operator
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
- BLACKROAD_GATEWAY_URL=http://core:8787
|
||||||
|
depends_on:
|
||||||
|
- core
|
||||||
|
networks:
|
||||||
|
- blackroad
|
||||||
|
profiles:
|
||||||
|
- tools
|
||||||
|
|
||||||
|
networks:
|
||||||
|
blackroad:
|
||||||
|
driver: bridge
|
||||||
9
docker/operator/Dockerfile
Normal file
9
docker/operator/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
RUN npm link
|
||||||
|
ENTRYPOINT ["br"]
|
||||||
16
docker/web/Dockerfile
Normal file
16
docker/web/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:22-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY --from=builder /app/.next/standalone ./
|
||||||
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "server.js"]
|
||||||
50
scripts/bootstrap.sh
Executable file
50
scripts/bootstrap.sh
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
# Bootstrap a new development environment with required tools.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||||
|
log() { echo -e "${GREEN}✓${NC} $1"; }
|
||||||
|
warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
||||||
|
fail() { echo -e "${RED}✗${NC} $1" >&2; exit 1; }
|
||||||
|
|
||||||
|
echo "BlackRoad Infra — Bootstrap"
|
||||||
|
echo "==========================="
|
||||||
|
|
||||||
|
# Check Node.js
|
||||||
|
if command -v node &>/dev/null; then
|
||||||
|
log "Node.js $(node -v)"
|
||||||
|
else
|
||||||
|
fail "Node.js not found. Install Node.js 22+."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Terraform
|
||||||
|
if command -v terraform &>/dev/null; then
|
||||||
|
log "Terraform $(terraform version -json | jq -r .terraform_version)"
|
||||||
|
else
|
||||||
|
warn "Terraform not found. Install: brew install terraform"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Docker
|
||||||
|
if command -v docker &>/dev/null; then
|
||||||
|
log "Docker $(docker --version | awk '{print $3}')"
|
||||||
|
else
|
||||||
|
warn "Docker not found. Install Docker Desktop."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Wrangler
|
||||||
|
if command -v wrangler &>/dev/null; then
|
||||||
|
log "Wrangler installed"
|
||||||
|
else
|
||||||
|
warn "Wrangler not found. Install: npm i -g wrangler"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check GitHub CLI
|
||||||
|
if command -v gh &>/dev/null; then
|
||||||
|
log "GitHub CLI $(gh --version | head -1 | awk '{print $3}')"
|
||||||
|
else
|
||||||
|
warn "GitHub CLI not found. Install: brew install gh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log "Bootstrap complete."
|
||||||
27
scripts/health-check.sh
Executable file
27
scripts/health-check.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
# Health check all BlackRoad services.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
|
||||||
|
ok() { echo -e "${GREEN}✓${NC} $1"; }
|
||||||
|
fail() { echo -e "${RED}✗${NC} $1"; }
|
||||||
|
|
||||||
|
echo "BlackRoad Health Check"
|
||||||
|
echo "======================"
|
||||||
|
|
||||||
|
check_url() {
|
||||||
|
local name="$1" url="$2"
|
||||||
|
if curl -sf --max-time 5 "$url" > /dev/null 2>&1; then
|
||||||
|
ok "$name ($url)"
|
||||||
|
else
|
||||||
|
fail "$name ($url)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_url "Gateway" "${BLACKROAD_GATEWAY_URL:-http://127.0.0.1:8787}/v1/health"
|
||||||
|
check_url "Web" "${BLACKROAD_WEB_URL:-http://127.0.0.1:3000}"
|
||||||
|
check_url "Agents" "${BLACKROAD_AGENTS_URL:-http://127.0.0.1:8788}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done."
|
||||||
20
scripts/rotate-keys.sh
Executable file
20
scripts/rotate-keys.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
# Key rotation helper — generates new secrets and updates .env files.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "BlackRoad Key Rotation"
|
||||||
|
echo "======================"
|
||||||
|
|
||||||
|
generate_key() {
|
||||||
|
openssl rand -hex 32
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Generating new keys..."
|
||||||
|
echo ""
|
||||||
|
echo "GATEWAY_SECRET=$(generate_key)"
|
||||||
|
echo "JWT_SECRET=$(generate_key)"
|
||||||
|
echo "SESSION_SECRET=$(generate_key)"
|
||||||
|
echo ""
|
||||||
|
echo "Copy the values above into your .env file."
|
||||||
|
echo "Remember to restart services after updating keys."
|
||||||
17
terraform/environments/production/backend.tf
Normal file
17
terraform/environments/production/backend.tf
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
# Using Cloudflare R2 as S3-compatible backend
|
||||||
|
terraform {
|
||||||
|
backend "s3" {
|
||||||
|
bucket = "blackroad-terraform-state"
|
||||||
|
key = "production/terraform.tfstate"
|
||||||
|
region = "auto"
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
skip_region_validation = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
|
skip_s3_checksum = true
|
||||||
|
endpoints = {
|
||||||
|
s3 = "https://848cf0b18d51e0170e0d1537aec3505a.r2.cloudflarestorage.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
terraform/environments/production/main.tf
Normal file
54
terraform/environments/production/main.tf
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 1.7"
|
||||||
|
required_providers {
|
||||||
|
cloudflare = {
|
||||||
|
source = "cloudflare/cloudflare"
|
||||||
|
version = "~> 4.0"
|
||||||
|
}
|
||||||
|
digitalocean = {
|
||||||
|
source = "digitalocean/digitalocean"
|
||||||
|
version = "~> 2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "cloudflare" {
|
||||||
|
api_token = var.cloudflare_api_token
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "digitalocean" {
|
||||||
|
token = var.digitalocean_token
|
||||||
|
}
|
||||||
|
|
||||||
|
module "gateway_pages" {
|
||||||
|
source = "../../modules/cloudflare-pages"
|
||||||
|
project_name = "blackroad-gateway"
|
||||||
|
build_command = "npm run build"
|
||||||
|
destination_dir = "dist"
|
||||||
|
account_id = var.cloudflare_account_id
|
||||||
|
}
|
||||||
|
|
||||||
|
module "web_pages" {
|
||||||
|
source = "../../modules/cloudflare-pages"
|
||||||
|
project_name = "blackroad-web"
|
||||||
|
build_command = "npm run build"
|
||||||
|
destination_dir = ".next"
|
||||||
|
account_id = var.cloudflare_account_id
|
||||||
|
}
|
||||||
|
|
||||||
|
module "gateway_worker" {
|
||||||
|
source = "../../modules/cloudflare-worker"
|
||||||
|
name = "blackroad-gateway"
|
||||||
|
script_path = "${path.module}/../../../docker/core/dist/index.js"
|
||||||
|
account_id = var.cloudflare_account_id
|
||||||
|
}
|
||||||
|
|
||||||
|
module "primary_droplet" {
|
||||||
|
source = "../../modules/digitalocean-droplet"
|
||||||
|
name = "blackroad-production"
|
||||||
|
region = var.do_region
|
||||||
|
size = var.do_size
|
||||||
|
image = "ubuntu-24-04-x64"
|
||||||
|
ssh_keys = var.do_ssh_keys
|
||||||
|
}
|
||||||
35
terraform/environments/production/variables.tf
Normal file
35
terraform/environments/production/variables.tf
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "cloudflare_api_token" {
|
||||||
|
description = "Cloudflare API token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cloudflare_account_id" {
|
||||||
|
description = "Cloudflare account ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "digitalocean_token" {
|
||||||
|
description = "DigitalOcean API token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "do_region" {
|
||||||
|
description = "DigitalOcean region"
|
||||||
|
type = string
|
||||||
|
default = "nyc3"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "do_size" {
|
||||||
|
description = "DigitalOcean droplet size"
|
||||||
|
type = string
|
||||||
|
default = "s-2vcpu-4gb"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "do_ssh_keys" {
|
||||||
|
description = "SSH key fingerprints for droplet access"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
16
terraform/environments/staging/backend.tf
Normal file
16
terraform/environments/staging/backend.tf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
terraform {
|
||||||
|
backend "s3" {
|
||||||
|
bucket = "blackroad-terraform-state"
|
||||||
|
key = "staging/terraform.tfstate"
|
||||||
|
region = "auto"
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
skip_region_validation = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
|
skip_s3_checksum = true
|
||||||
|
endpoints = {
|
||||||
|
s3 = "https://848cf0b18d51e0170e0d1537aec3505a.r2.cloudflarestorage.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
terraform/environments/staging/main.tf
Normal file
39
terraform/environments/staging/main.tf
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 1.7"
|
||||||
|
required_providers {
|
||||||
|
cloudflare = {
|
||||||
|
source = "cloudflare/cloudflare"
|
||||||
|
version = "~> 4.0"
|
||||||
|
}
|
||||||
|
digitalocean = {
|
||||||
|
source = "digitalocean/digitalocean"
|
||||||
|
version = "~> 2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "cloudflare" {
|
||||||
|
api_token = var.cloudflare_api_token
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "digitalocean" {
|
||||||
|
token = var.digitalocean_token
|
||||||
|
}
|
||||||
|
|
||||||
|
module "gateway_pages" {
|
||||||
|
source = "../../modules/cloudflare-pages"
|
||||||
|
project_name = "blackroad-gateway-staging"
|
||||||
|
build_command = "npm run build"
|
||||||
|
destination_dir = "dist"
|
||||||
|
account_id = var.cloudflare_account_id
|
||||||
|
}
|
||||||
|
|
||||||
|
module "staging_droplet" {
|
||||||
|
source = "../../modules/digitalocean-droplet"
|
||||||
|
name = "blackroad-staging"
|
||||||
|
region = var.do_region
|
||||||
|
size = "s-1vcpu-1gb"
|
||||||
|
image = "ubuntu-24-04-x64"
|
||||||
|
ssh_keys = var.do_ssh_keys
|
||||||
|
}
|
||||||
29
terraform/environments/staging/variables.tf
Normal file
29
terraform/environments/staging/variables.tf
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "cloudflare_api_token" {
|
||||||
|
description = "Cloudflare API token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cloudflare_account_id" {
|
||||||
|
description = "Cloudflare account ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "digitalocean_token" {
|
||||||
|
description = "DigitalOcean API token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "do_region" {
|
||||||
|
description = "DigitalOcean region"
|
||||||
|
type = string
|
||||||
|
default = "nyc3"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "do_ssh_keys" {
|
||||||
|
description = "SSH key fingerprints"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
17
terraform/modules/cloudflare-pages/main.tf
Normal file
17
terraform/modules/cloudflare-pages/main.tf
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
resource "cloudflare_pages_project" "this" {
|
||||||
|
account_id = var.account_id
|
||||||
|
name = var.project_name
|
||||||
|
production_branch = "main"
|
||||||
|
|
||||||
|
build_config {
|
||||||
|
build_command = var.build_command
|
||||||
|
destination_dir = var.destination_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment_configs {
|
||||||
|
production {
|
||||||
|
environment_variables = var.environment_variables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
terraform/modules/cloudflare-pages/outputs.tf
Normal file
10
terraform/modules/cloudflare-pages/outputs.tf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
output "url" {
|
||||||
|
description = "Pages project URL"
|
||||||
|
value = "https://${cloudflare_pages_project.this.name}.pages.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "project_id" {
|
||||||
|
description = "Pages project ID"
|
||||||
|
value = cloudflare_pages_project.this.id
|
||||||
|
}
|
||||||
28
terraform/modules/cloudflare-pages/variables.tf
Normal file
28
terraform/modules/cloudflare-pages/variables.tf
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "account_id" {
|
||||||
|
description = "Cloudflare account ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "project_name" {
|
||||||
|
description = "Pages project name"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "build_command" {
|
||||||
|
description = "Build command"
|
||||||
|
type = string
|
||||||
|
default = "npm run build"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "destination_dir" {
|
||||||
|
description = "Build output directory"
|
||||||
|
type = string
|
||||||
|
default = "dist"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "environment_variables" {
|
||||||
|
description = "Environment variables for production"
|
||||||
|
type = map(string)
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
14
terraform/modules/cloudflare-worker/main.tf
Normal file
14
terraform/modules/cloudflare-worker/main.tf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
resource "cloudflare_worker_script" "this" {
|
||||||
|
account_id = var.account_id
|
||||||
|
name = var.name
|
||||||
|
content = file(var.script_path)
|
||||||
|
module = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_worker_route" "this" {
|
||||||
|
count = var.route_pattern != "" ? 1 : 0
|
||||||
|
zone_id = var.zone_id
|
||||||
|
pattern = var.route_pattern
|
||||||
|
script_name = cloudflare_worker_script.this.name
|
||||||
|
}
|
||||||
5
terraform/modules/cloudflare-worker/outputs.tf
Normal file
5
terraform/modules/cloudflare-worker/outputs.tf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
output "worker_name" {
|
||||||
|
description = "Deployed worker name"
|
||||||
|
value = cloudflare_worker_script.this.name
|
||||||
|
}
|
||||||
27
terraform/modules/cloudflare-worker/variables.tf
Normal file
27
terraform/modules/cloudflare-worker/variables.tf
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "account_id" {
|
||||||
|
description = "Cloudflare account ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "name" {
|
||||||
|
description = "Worker script name"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "script_path" {
|
||||||
|
description = "Path to the worker script file"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "zone_id" {
|
||||||
|
description = "Cloudflare zone ID for route binding"
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "route_pattern" {
|
||||||
|
description = "URL pattern for worker route"
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
45
terraform/modules/digitalocean-droplet/main.tf
Normal file
45
terraform/modules/digitalocean-droplet/main.tf
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
resource "digitalocean_droplet" "this" {
|
||||||
|
name = var.name
|
||||||
|
region = var.region
|
||||||
|
size = var.size
|
||||||
|
image = var.image
|
||||||
|
ssh_keys = var.ssh_keys
|
||||||
|
|
||||||
|
tags = concat(["blackroad"], var.tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "digitalocean_firewall" "this" {
|
||||||
|
name = "${var.name}-fw"
|
||||||
|
droplet_ids = [digitalocean_droplet.this.id]
|
||||||
|
|
||||||
|
inbound_rule {
|
||||||
|
protocol = "tcp"
|
||||||
|
port_range = "22"
|
||||||
|
source_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
inbound_rule {
|
||||||
|
protocol = "tcp"
|
||||||
|
port_range = "80"
|
||||||
|
source_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
inbound_rule {
|
||||||
|
protocol = "tcp"
|
||||||
|
port_range = "443"
|
||||||
|
source_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound_rule {
|
||||||
|
protocol = "tcp"
|
||||||
|
port_range = "all"
|
||||||
|
destination_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound_rule {
|
||||||
|
protocol = "udp"
|
||||||
|
port_range = "all"
|
||||||
|
destination_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
15
terraform/modules/digitalocean-droplet/outputs.tf
Normal file
15
terraform/modules/digitalocean-droplet/outputs.tf
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
output "id" {
|
||||||
|
description = "Droplet ID"
|
||||||
|
value = digitalocean_droplet.this.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ipv4_address" {
|
||||||
|
description = "Public IPv4 address"
|
||||||
|
value = digitalocean_droplet.this.ipv4_address
|
||||||
|
}
|
||||||
|
|
||||||
|
output "name" {
|
||||||
|
description = "Droplet name"
|
||||||
|
value = digitalocean_droplet.this.name
|
||||||
|
}
|
||||||
35
terraform/modules/digitalocean-droplet/variables.tf
Normal file
35
terraform/modules/digitalocean-droplet/variables.tf
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "name" {
|
||||||
|
description = "Droplet name"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "region" {
|
||||||
|
description = "DigitalOcean region"
|
||||||
|
type = string
|
||||||
|
default = "nyc3"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "size" {
|
||||||
|
description = "Droplet size slug"
|
||||||
|
type = string
|
||||||
|
default = "s-2vcpu-4gb"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "image" {
|
||||||
|
description = "Droplet image"
|
||||||
|
type = string
|
||||||
|
default = "ubuntu-24-04-x64"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_keys" {
|
||||||
|
description = "SSH key fingerprints"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
description = "Additional tags"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
20
terraform/modules/railway-service/main.tf
Normal file
20
terraform/modules/railway-service/main.tf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
# Railway does not have an official Terraform provider.
|
||||||
|
# We use null_resource with local-exec to deploy via the Railway CLI.
|
||||||
|
resource "null_resource" "railway_deploy" {
|
||||||
|
triggers = {
|
||||||
|
service_name = var.service_name
|
||||||
|
project_id = var.project_id
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "local-exec" {
|
||||||
|
command = <<-EOT
|
||||||
|
railway link ${var.project_id}
|
||||||
|
railway up --service ${var.service_name}
|
||||||
|
EOT
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
RAILWAY_TOKEN = var.railway_token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
terraform/modules/railway-service/outputs.tf
Normal file
5
terraform/modules/railway-service/outputs.tf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
output "service_name" {
|
||||||
|
description = "Deployed Railway service name"
|
||||||
|
value = var.service_name
|
||||||
|
}
|
||||||
16
terraform/modules/railway-service/variables.tf
Normal file
16
terraform/modules/railway-service/variables.tf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
||||||
|
variable "railway_token" {
|
||||||
|
description = "Railway API token"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "project_id" {
|
||||||
|
description = "Railway project ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "service_name" {
|
||||||
|
description = "Service name within the project"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user