-
Notifications
You must be signed in to change notification settings - Fork 0
156 lines (133 loc) · 5.2 KB
/
Copy pathci.yml
File metadata and controls
156 lines (133 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
name: CI — MedTech Platform
on:
push:
branches: [main, develop]
paths-ignore:
- 'docs/**'
- '**/*.md'
pull_request:
branches: [main]
paths-ignore:
- 'docs/**'
- '**/*.md'
schedule:
- cron: '0 2 * * *'
jobs:
# ── Lint ────────────────────────────────────────────────────────────────────
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate docker-compose syntax
run: |
docker compose -f docker-compose.yml config --quiet
docker compose -f docker-compose.yml -f docker-compose.build.yml config --quiet
- name: Validate all YAML files in .github/
run: |
python3 - <<'EOF'
import yaml, sys, pathlib
errors = []
for f in pathlib.Path('.github').rglob('*.yml'):
try:
yaml.safe_load(f.read_text())
except yaml.YAMLError as e:
errors.append(f"{f}: {e}")
if errors:
print('\n'.join(errors), file=sys.stderr)
sys.exit(1)
print(f"✅ All YAML files valid")
EOF
- name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
continue-on-error: true
# ── Test ─────────────────────────────────────────────────────────────────────
test:
name: Test
runs-on: ubuntu-latest
needs: [lint]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Check Python test file syntax
run: python3 -m py_compile tests/integration_test.py
- name: Validate compose override merges cleanly
run: |
# Ensure build override is compatible with the base compose file
docker compose \
-f docker-compose.yml \
-f docker-compose.build.yml \
config --quiet
# ── Security ─────────────────────────────────────────────────────────────────
security:
name: Security scan
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Check for hardcoded secrets in compose files
run: |
if grep -rEn "(password|secret|api_key)\s*[:=]\s*['\"][^'\"]{8,}" \
docker-compose.yml docker-compose.build.yml 2>/dev/null; then
echo "::warning::Possible hardcoded secret detected in compose files"
fi
- name: Run Trivy vulnerability scan on Dockerfile
uses: aquasecurity/trivy-action@master
with:
scan-type: config
scan-ref: .
exit-code: '0' # advisory only — do not fail CI
format: table
continue-on-error: true
# ── Smoke-test ───────────────────────────────────────────────────────────────
smoke-test:
name: Smoke-test platform stack
runs-on: ubuntu-latest
needs: [lint, test]
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Authenticate so the composite action can pull the pinned service images
# from GHCR (vitals-publisher, edge-analytics, clinician-ui).
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build platform image (local, not pushed)
uses: docker/build-push-action@v5
with:
context: .
push: false
load: true
tags: medtech-platform:ci
cache-from: type=gha
cache-to: type=gha,mode=max
# registry-token is intentionally omitted — the runner is already
# authenticated from the Login step above.
- name: Run smoke tests
uses: ./.github/actions/smoke-test
with:
image: medtech-platform:ci
# ── Status gate ──────────────────────────────────────────────────────────────
status:
name: CI Status
runs-on: ubuntu-latest
needs: [lint, test, security, smoke-test]
if: always()
steps:
- name: Evaluate required job results
run: |
if [[ "${{ needs.lint.result }}" != "success" ]] || \
[[ "${{ needs.smoke-test.result }}" != "success" ]]; then
echo "::error::Required CI jobs failed (lint: ${{ needs.lint.result }}, smoke-test: ${{ needs.smoke-test.result }})"
exit 1
fi
echo "✅ All required checks passed"