Skip to content

Commit 69d1cb2

Browse files
committed
updates and build out
1 parent 4a0a6d6 commit 69d1cb2

56 files changed

Lines changed: 4552 additions & 54 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,34 @@ name: CI
22

33
on:
44
push:
5-
branches: [ main, master ]
5+
branches: [main, master]
66
pull_request:
7-
branches: [ main, master ]
7+
branches: [main, master]
8+
9+
env:
10+
REGISTRY: ghcr.io
11+
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}/wildfire
812

913
jobs:
14+
# ── Node.js workspace ─────────────────────────────────────────────
1015
node:
1116
name: Node.js (TypeScript)
1217
runs-on: ubuntu-latest
1318
steps:
1419
- name: Checkout
1520
uses: actions/checkout@v4
1621

17-
- name: Setup Node.js
18-
uses: actions/setup-node@v4
19-
with:
20-
node-version: '18'
21-
cache: 'pnpm'
22-
2322
- name: Setup pnpm
2423
uses: pnpm/action-setup@v2
2524
with:
2625
version: 8
2726

27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: "18"
31+
cache: pnpm
32+
2833
- name: Install dependencies
2934
run: pnpm install --frozen-lockfile
3035

@@ -36,14 +41,18 @@ jobs:
3641

3742
- name: Build
3843
run: pnpm build
39-
44+
45+
- name: Test
46+
run: pnpm test
47+
48+
# ── Python services ───────────────────────────────────────────────
4049
python:
4150
name: Python (FastAPI)
4251
runs-on: ubuntu-latest
4352
defaults:
4453
run:
4554
working-directory: apps/apigw
46-
55+
4756
services:
4857
postgres:
4958
image: postgis/postgis:15-3.3
@@ -58,7 +67,7 @@ jobs:
5867
--health-interval 10s
5968
--health-timeout 5s
6069
--health-retries 5
61-
70+
6271
redis:
6372
image: redis:7-alpine
6473
ports:
@@ -68,32 +77,30 @@ jobs:
6877
--health-interval 10s
6978
--health-timeout 5s
7079
--health-retries 5
71-
80+
7281
steps:
7382
- name: Checkout
7483
uses: actions/checkout@v4
75-
84+
7685
- name: Setup Python
7786
uses: actions/setup-python@v5
7887
with:
79-
python-version: '3.11'
80-
cache: 'pip'
88+
python-version: "3.11"
89+
cache: pip
8190
cache-dependency-path: apps/apigw/requirements.txt
82-
91+
8392
- name: Install dependencies
8493
run: |
8594
python -m pip install --upgrade pip
8695
pip install -r requirements.txt
8796
pip install pytest pytest-asyncio pytest-cov mypy ruff
88-
97+
8998
- name: Lint with ruff
9099
run: ruff check app/ --output-format=github
91-
continue-on-error: true
92-
100+
93101
- name: Type check with mypy
94102
run: mypy app/ --ignore-missing-imports --no-strict-optional
95-
continue-on-error: true
96-
103+
97104
- name: Run tests
98105
env:
99106
DATABASE_URL: postgresql://wildfire:wildfire123@localhost:5432/wildfire_ops_test
@@ -103,11 +110,70 @@ jobs:
103110
SECRET_KEY: test-secret-key
104111
run: |
105112
pytest tests/ -v --cov=app --cov-report=term-missing --cov-report=xml
106-
113+
107114
- name: Upload coverage
108115
uses: codecov/codecov-action@v3
109116
if: always()
110117
with:
111118
files: ./apps/apigw/coverage.xml
112119
flags: python
113120
name: python-coverage
121+
122+
# ── Docker build verification ─────────────────────────────────────
123+
docker:
124+
name: Docker Build
125+
runs-on: ubuntu-latest
126+
needs: [node, python]
127+
strategy:
128+
fail-fast: false
129+
matrix:
130+
service:
131+
- { name: apigw, context: ./apps/apigw, dockerfile: ./apps/apigw/Dockerfile }
132+
- { name: console, context: ./apps/console, dockerfile: ./apps/console/Dockerfile }
133+
- { name: triangulate, context: ".", dockerfile: ./apps/triangulate/Dockerfile }
134+
- { name: predict, context: ".", dockerfile: ./apps/predict/Dockerfile }
135+
- { name: ingest, context: ".", dockerfile: ./apps/ingest/Dockerfile }
136+
- { name: mission-dispatcher, context: ".", dockerfile: ./apps/mission-dispatcher/Dockerfile }
137+
- { name: edge-agent, context: ./apps/edge-agent, dockerfile: ./apps/edge-agent/Dockerfile }
138+
steps:
139+
- name: Checkout
140+
uses: actions/checkout@v4
141+
142+
- name: Set up Docker Buildx
143+
uses: docker/setup-buildx-action@v3
144+
145+
- name: Build image (no push)
146+
uses: docker/build-push-action@v5
147+
with:
148+
context: ${{ matrix.service.context }}
149+
file: ${{ matrix.service.dockerfile }}
150+
push: false
151+
tags: ${{ env.IMAGE_PREFIX }}-${{ matrix.service.name }}:ci-${{ github.sha }}
152+
cache-from: type=gha
153+
cache-to: type=gha,mode=max
154+
155+
# ── Security scanning ────────────────────────────────────────────
156+
security:
157+
name: Security Scan
158+
runs-on: ubuntu-latest
159+
needs: [node, python]
160+
steps:
161+
- name: Checkout
162+
uses: actions/checkout@v4
163+
164+
- name: Run Trivy vulnerability scanner (filesystem)
165+
uses: aquasecurity/trivy-action@master
166+
with:
167+
scan-type: fs
168+
scan-ref: "."
169+
severity: CRITICAL,HIGH
170+
exit-code: "1"
171+
ignore-unfixed: true
172+
173+
- name: Run Trivy config scan (IaC)
174+
uses: aquasecurity/trivy-action@master
175+
with:
176+
scan-type: config
177+
scan-ref: infra/
178+
severity: CRITICAL,HIGH
179+
exit-code: "0"

.github/workflows/deploy.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: Deploy
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
inputs:
8+
environment:
9+
description: "Target environment"
10+
required: true
11+
type: choice
12+
options:
13+
- staging
14+
- production
15+
16+
env:
17+
REGISTRY: ghcr.io
18+
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}/wildfire
19+
20+
permissions:
21+
contents: read
22+
packages: write
23+
24+
jobs:
25+
# ── Build & push images ──────────────────────────────────────────
26+
build:
27+
name: Build & Push
28+
runs-on: ubuntu-latest
29+
strategy:
30+
fail-fast: true
31+
matrix:
32+
service:
33+
- { name: apigw, context: ./apps/apigw, dockerfile: ./apps/apigw/Dockerfile }
34+
- { name: console, context: ./apps/console, dockerfile: ./apps/console/Dockerfile }
35+
- { name: triangulate, context: ".", dockerfile: ./apps/triangulate/Dockerfile }
36+
- { name: predict, context: ".", dockerfile: ./apps/predict/Dockerfile }
37+
- { name: ingest, context: ".", dockerfile: ./apps/ingest/Dockerfile }
38+
- { name: mission-dispatcher, context: ".", dockerfile: ./apps/mission-dispatcher/Dockerfile }
39+
- { name: edge-agent, context: ./apps/edge-agent, dockerfile: ./apps/edge-agent/Dockerfile }
40+
outputs:
41+
image_tag: ${{ steps.meta.outputs.tags }}
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@v4
45+
46+
- name: Set up Docker Buildx
47+
uses: docker/setup-buildx-action@v3
48+
49+
- name: Login to GHCR
50+
uses: docker/login-action@v3
51+
with:
52+
registry: ${{ env.REGISTRY }}
53+
username: ${{ github.actor }}
54+
password: ${{ secrets.GITHUB_TOKEN }}
55+
56+
- name: Docker metadata
57+
id: meta
58+
uses: docker/metadata-action@v5
59+
with:
60+
images: ${{ env.IMAGE_PREFIX }}-${{ matrix.service.name }}
61+
tags: |
62+
type=sha
63+
type=ref,event=branch
64+
type=raw,value=latest,enable={{is_default_branch}}
65+
66+
- name: Build and push
67+
uses: docker/build-push-action@v5
68+
with:
69+
context: ${{ matrix.service.context }}
70+
file: ${{ matrix.service.dockerfile }}
71+
push: true
72+
tags: ${{ steps.meta.outputs.tags }}
73+
labels: ${{ steps.meta.outputs.labels }}
74+
cache-from: type=gha
75+
cache-to: type=gha,mode=max
76+
77+
# ── Deploy to staging (auto on main push) ────────────────────────
78+
staging:
79+
name: Deploy to Staging
80+
needs: build
81+
runs-on: ubuntu-latest
82+
if: github.ref == 'refs/heads/main' || github.event.inputs.environment == 'staging'
83+
environment:
84+
name: staging
85+
url: https://staging.wildfire-ops.com
86+
steps:
87+
- name: Checkout
88+
uses: actions/checkout@v4
89+
90+
- name: Configure kubectl
91+
uses: azure/setup-kubectl@v3
92+
93+
- name: Set kubeconfig
94+
run: echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > $HOME/.kube/config
95+
96+
- name: Update image tags
97+
run: |
98+
TAG="sha-${GITHUB_SHA::7}"
99+
for svc in apigw console triangulate predict ingest mission-dispatcher edge-agent; do
100+
kubectl set image deployment/${svc} \
101+
${svc}=${{ env.IMAGE_PREFIX }}-${svc}:${TAG} \
102+
-n wildfire-ops --record || true
103+
done
104+
105+
- name: Wait for rollout
106+
run: |
107+
for svc in apigw console triangulate predict ingest; do
108+
kubectl rollout status deployment/${svc} -n wildfire-ops --timeout=300s
109+
done
110+
111+
- name: Run smoke tests
112+
run: |
113+
API_URL="${{ secrets.STAGING_API_URL }}"
114+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${API_URL}/health")
115+
if [ "$STATUS" != "200" ]; then
116+
echo "Smoke test failed: API returned $STATUS"
117+
exit 1
118+
fi
119+
echo "Staging smoke test passed"
120+
121+
# ── Deploy to production (manual approval required) ──────────────
122+
production:
123+
name: Deploy to Production
124+
needs: staging
125+
runs-on: ubuntu-latest
126+
if: github.event.inputs.environment == 'production' || github.ref == 'refs/heads/main'
127+
environment:
128+
name: production
129+
url: https://console.wildfire-ops.com
130+
steps:
131+
- name: Checkout
132+
uses: actions/checkout@v4
133+
134+
- name: Configure kubectl
135+
uses: azure/setup-kubectl@v3
136+
137+
- name: Set kubeconfig
138+
run: echo "${{ secrets.KUBE_CONFIG_PRODUCTION }}" | base64 -d > $HOME/.kube/config
139+
140+
- name: Update image tags (canary — 1 replica first)
141+
run: |
142+
TAG="sha-${GITHUB_SHA::7}"
143+
for svc in apigw console triangulate predict ingest mission-dispatcher edge-agent; do
144+
kubectl set image deployment/${svc} \
145+
${svc}=${{ env.IMAGE_PREFIX }}-${svc}:${TAG} \
146+
-n wildfire-ops --record || true
147+
done
148+
149+
- name: Wait for rollout
150+
run: |
151+
for svc in apigw console triangulate predict ingest; do
152+
kubectl rollout status deployment/${svc} -n wildfire-ops --timeout=600s
153+
done
154+
155+
- name: Production smoke test
156+
run: |
157+
API_URL="${{ secrets.PRODUCTION_API_URL }}"
158+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${API_URL}/health")
159+
if [ "$STATUS" != "200" ]; then
160+
echo "Production smoke test FAILED — rolling back"
161+
for svc in apigw console triangulate predict ingest mission-dispatcher edge-agent; do
162+
kubectl rollout undo deployment/${svc} -n wildfire-ops || true
163+
done
164+
exit 1
165+
fi
166+
echo "Production deploy successful"

0 commit comments

Comments
 (0)