Skip to content

Commit a8a1fec

Browse files
authored
Merge pull request #1 from lissy93-forks/add-ci-cd-workflows
Adds CI/CD workflows
2 parents 2eefca2 + 3773437 commit a8a1fec

8 files changed

Lines changed: 1083 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# CI checks to run when a PR is opened, or manually via workflow_dispatch
2+
name: 🚦 CI
3+
4+
on:
5+
pull_request:
6+
branches: ['main']
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
changes:
18+
name: 🔎 Detect Changes
19+
runs-on: ubuntu-latest
20+
outputs:
21+
lockfile: ${{ steps.filter.outputs.lockfile }}
22+
workflows: ${{ steps.filter.outputs.workflows }}
23+
steps:
24+
- name: Checkout Code
25+
uses: actions/checkout@v6
26+
27+
- name: Filter Paths
28+
uses: dorny/paths-filter@v4
29+
id: filter
30+
with:
31+
filters: |
32+
lockfile:
33+
- 'yarn.lock'
34+
- 'package.json'
35+
- 'papervault-*/package.json'
36+
- 'papervault-*/package-lock.json'
37+
workflows:
38+
- '.github/workflows/**'
39+
40+
test:
41+
name: 🧪 Test
42+
runs-on: ubuntu-latest
43+
steps:
44+
- name: Checkout Code
45+
uses: actions/checkout@v6
46+
47+
- name: Setup Node.js
48+
uses: actions/setup-node@v6
49+
with:
50+
node-version: '24'
51+
cache: 'yarn'
52+
53+
- name: Install Dependencies
54+
run: yarn install --frozen-lockfile
55+
56+
- name: Run Tests
57+
run: yarn test --watchAll=false
58+
59+
build:
60+
name: 🏗️ Build Check
61+
runs-on: ubuntu-latest
62+
steps:
63+
- name: Checkout Code
64+
uses: actions/checkout@v6
65+
66+
- name: Setup Node.js
67+
uses: actions/setup-node@v6
68+
with:
69+
node-version: '24'
70+
cache: 'yarn'
71+
72+
- name: Install Dependencies
73+
run: yarn install --frozen-lockfile
74+
75+
- name: Build Project
76+
run: yarn build
77+
78+
- name: Verify Build Output
79+
run: |
80+
if [ ! -d "build" ]; then
81+
echo "❌ Build failed: build directory not created"
82+
exit 1
83+
fi
84+
if [ ! -f "build/index.html" ]; then
85+
echo "❌ Build failed: index.html not found"
86+
exit 1
87+
fi
88+
echo "✅ Build successful"
89+
90+
docker-smoke:
91+
name: 🐳 Docker Smoke Test
92+
runs-on: ubuntu-latest
93+
continue-on-error: true
94+
steps:
95+
- name: Checkout Code
96+
uses: actions/checkout@v6
97+
98+
- name: Build & Test Docker Image
99+
timeout-minutes: 10
100+
run: |
101+
set -euo pipefail
102+
docker build -t papervault-smoke .
103+
docker run -d --rm --name papervault-smoke -p 3000:3000 papervault-smoke
104+
trap 'docker stop papervault-smoke >/dev/null 2>&1 || true' EXIT
105+
for i in $(seq 1 30); do
106+
if curl -sf http://localhost:3000/ >/dev/null; then break; fi
107+
if [ "$i" = "30" ]; then
108+
echo "❌ App did not respond within 30s"
109+
docker logs papervault-smoke
110+
exit 1
111+
fi
112+
sleep 1
113+
done
114+
curl -sf http://localhost:3000/ | grep -qi '<div id="root"'
115+
echo "✅ Docker image builds and serves the app"
116+
117+
dependency-review:
118+
name: 🔒 Dependency Audit
119+
runs-on: ubuntu-latest
120+
needs: changes
121+
if: needs.changes.outputs.lockfile == 'true' && github.event_name == 'pull_request'
122+
permissions:
123+
contents: read
124+
steps:
125+
- name: Checkout Code
126+
uses: actions/checkout@v6
127+
128+
- name: Review Dependencies
129+
uses: actions/dependency-review-action@v5
130+
with:
131+
fail-on-severity: moderate
132+
133+
secret-scan:
134+
name: 🔑 Secret Scanning
135+
runs-on: ubuntu-latest
136+
permissions:
137+
contents: read
138+
steps:
139+
- name: Checkout Code
140+
uses: actions/checkout@v6
141+
with:
142+
fetch-depth: 0
143+
144+
- name: Scan PR Diff for Secrets
145+
uses: trufflesecurity/trufflehog@v3.95.5
146+
with:
147+
base: ${{ github.event.pull_request.base.sha }}
148+
head: ${{ github.event.pull_request.head.sha }}
149+
extra_args: --only-verified
150+
151+
workflow-audit:
152+
name: 🛠️ Workflow Audit
153+
runs-on: ubuntu-latest
154+
needs: changes
155+
if: needs.changes.outputs.workflows == 'true' || github.event_name == 'workflow_dispatch'
156+
steps:
157+
- name: Checkout Code
158+
uses: actions/checkout@v6
159+
160+
- name: Run Actionlint
161+
uses: raven-actions/actionlint@v2
162+
with:
163+
fail-on-error: true
164+
165+
- name: Run Zizmor
166+
uses: zizmorcore/zizmor-action@v0.5.6
167+
with:
168+
inputs: .github/workflows/
169+
advanced-security: false
170+
annotations: true
171+
172+
# Renders markdown summary of all checks at the end
173+
summary:
174+
name: 📋 Summary
175+
runs-on: ubuntu-latest
176+
if: always()
177+
continue-on-error: true
178+
needs:
179+
- test
180+
- build
181+
- docker-smoke
182+
- dependency-review
183+
- secret-scan
184+
- workflow-audit
185+
steps:
186+
- name: Render Summary
187+
env:
188+
NEEDS: ${{ toJSON(needs) }}
189+
run: |
190+
label() {
191+
case "$1" in
192+
test) echo "🧪 Test" ;;
193+
build) echo "🏗️ Build" ;;
194+
docker-smoke) echo "🐳 Docker Smoke" ;;
195+
dependency-review) echo "🔒 Dependency Audit" ;;
196+
secret-scan) echo "🔑 Secret Scan" ;;
197+
workflow-audit) echo "🛠️ Workflow Audit" ;;
198+
*) echo "$1" ;;
199+
esac
200+
}
201+
status() {
202+
case "$1" in
203+
success) echo "✅ Passed" ;;
204+
skipped) echo "⏭️ Skipped" ;;
205+
cancelled) echo "🚫 Cancelled" ;;
206+
failure) [ "$2" = docker-smoke ] && echo "⚠️ Warnings" || echo "❌ Failed" ;;
207+
*) echo "❔ $1" ;;
208+
esac
209+
}
210+
{
211+
echo "## CI Summary"
212+
echo ""
213+
echo "| Check | Status |"
214+
echo "|-------|--------|"
215+
} >> "$GITHUB_STEP_SUMMARY"
216+
for job in $(echo "$NEEDS" | jq -r 'keys[]'); do
217+
result=$(echo "$NEEDS" | jq -r --arg j "$job" '.[$j].result')
218+
echo "| $(label "$job") | $(status "$result" "$job") |" >> "$GITHUB_STEP_SUMMARY"
219+
done

0 commit comments

Comments
 (0)