Skip to content

Commit 0b6a29e

Browse files
Add Devops audit report (Claude)
1 parent 0dc6b51 commit 0b6a29e

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

AUDIT_REPORT.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Repository Audit Report
2+
3+
**Date:** 2026-03-19
4+
**Branch:** sani-review
5+
**Scope:** Bugs, security issues, architecture problems, Docker/DevOps issues, CI/CD risks (Jenkins)
6+
7+
---
8+
9+
## CRITICAL
10+
11+
### C1 — Missing `path` import in `result/server.js` (Runtime Crash)
12+
**File:** `result/server.js:71`
13+
`res.sendFile(path.resolve(__dirname + "/views/index.html"))``path` is used but never imported with `require('path')`. Every GET `/` will throw a `ReferenceError`, making the result service completely broken in production.
14+
15+
### C2 — Hardcoded Database Credentials Everywhere
16+
**Files:**
17+
- `docker-compose.yml:67-68``POSTGRES_USER/PASSWORD: "postgres"`
18+
- `worker/Program.cs:19``"Server=db;Username=postgres;Password=postgres;"`
19+
- `result/server.js:21``"postgres://postgres:postgres@db/postgres"`
20+
- `k8s-specifications/db-deployment.yaml:23-24` — plain-text in YAML
21+
- `result/docker-compose.test.yml:49-51`
22+
23+
Credentials are in source control, visible to anyone. Should use environment variables + Kubernetes Secrets / Docker secrets.
24+
25+
### C3 — Docker Socket Mounted into Containers
26+
**Files:** `trivy-scan.sh:15-37`, `docker-compose.trivy.yml:9`
27+
`-v /var/run/docker.sock:/var/run/docker.sock` gives the container full control of the Docker daemon. A compromised container becomes a full host compromise.
28+
29+
### C4 — Jenkinsfile `|| true` Suppresses All Failures
30+
**File:** `Jenkinsfile` (lines ~46, 64, 73, 82, 92)
31+
Every critical step — linting, static analysis, security scanning — is suffixed with `|| true`. The pipeline will show green even when checks fail. Defeats the entire purpose of CI gates.
32+
33+
### C5 — PostgreSQL `emptyDir` in Kubernetes (Data Loss)
34+
**Files:** `k8s-specifications/db-deployment.yaml:33`, `k8s-specifications/redis-deployment.yaml:28`
35+
```yaml
36+
volumes:
37+
- name: db-data
38+
emptyDir: {} # wiped on every pod restart
39+
```
40+
All vote data is permanently lost on any pod restart or eviction. Needs a `PersistentVolumeClaim`.
41+
42+
---
43+
44+
## MEDIUM
45+
46+
### M1 — Flask Debug Mode in Production
47+
**File:** `vote/app.py:53`
48+
```python
49+
app.run(host='0.0.0.0', port=80, debug=True, threaded=True)
50+
```
51+
`debug=True` enables the Werkzeug interactive debugger — arbitrary code execution from the browser. Should use gunicorn (already in `requirements.txt`).
52+
53+
### M2 — No USER Directive in Any Dockerfile
54+
**Files:** `vote/Dockerfile`, `result/Dockerfile`, `worker/Dockerfile`, `seed-data/Dockerfile`
55+
All containers run as root. A container escape grants full host access. Add `USER nobody` or create a dedicated user.
56+
57+
### M3 — Unpinned Base Images
58+
**Files:** All Dockerfiles use tags like `python:3.11-slim`, `node:18-slim`, `mcr.microsoft.com/dotnet/sdk:7.0` — no SHA digest pinning. Builds are non-reproducible and silently pick up upstream changes.
59+
60+
### M4 — `result/tests/Dockerfile` Uses Node 8 (EOL 2019)
61+
**File:** `result/tests/Dockerfile:1` — `node:8.9-slim`. Critical CVEs, no patches. Upgrade to Node 18+.
62+
63+
### M5 — Test PostgreSQL Version Mismatch
64+
**File:** `result/docker-compose.test.yml:48` uses `postgres:9.4` (EOL 2021).
65+
**Production:** `docker-compose.yml` uses `postgres:15-alpine`. Tests don't reflect production behavior.
66+
67+
### M6 — Jenkinsfile Artifacts Reference Non-Existent Paths
68+
**File:** `Jenkinsfile:134-135`
69+
```groovy
70+
'result/dist/**/*' // no dist/ directory in result service
71+
'vote/build/**/*' // no build/ directory in vote service
72+
```
73+
Archive steps silently do nothing. No build output is preserved.
74+
75+
### M7 — JUnit Report Format Mismatch
76+
**File:** `Jenkinsfile:137` — `junit testResults: 'result/tests/test-report.txt'`
77+
`result/tests/tests.sh` writes plain text (`echo "Tests passed" >> test-report.txt`), not JUnit XML. Jenkins will fail or silently skip the report.
78+
79+
### M8 — Worker Has No Graceful Shutdown
80+
**File:** `worker/Program.cs:29-61` — `while(true)` loop with no `CancellationToken` or SIGTERM handler. Rolling deployments will SIGKILL the worker mid-vote, potentially losing votes in transit.
81+
82+
### M9 — No Resource Limits Anywhere
83+
**Files:** All `docker-compose.yml` services, all `k8s-specifications/*.yaml`
84+
No memory or CPU limits. A single misbehaving container can starve the host.
85+
86+
### M10 — No Liveness/Readiness Probes in Kubernetes
87+
**Files:** All `k8s-specifications/*-deployment.yaml`
88+
Kubernetes cannot detect unhealthy pods; broken instances stay in rotation and receive traffic.
89+
90+
### M11 — Nginx Has No HTTPS, No Security Headers, No Rate Limiting
91+
**File:** `nginx/nginx.conf`
92+
- HTTP only (port 80), all traffic in plaintext
93+
- Missing: `X-Frame-Options`, `X-Content-Type-Options`, `Content-Security-Policy`, HSTS
94+
- No `limit_req` — open to abuse/DDoS
95+
96+
### M12 — Duplicate Build Stages in Jenkinsfile
97+
**File:** `Jenkinsfile` — images are built once serially (lines ~30-38) then rebuilt again in a "parallel" stage (lines ~94-115). Wasted CI time and ambiguity about which artifact is tested.
98+
99+
### M13 — No `.dockerignore` Files
100+
No `.dockerignore` found in any service directory. `.git`, `node_modules`, test files, and local configs are copied into images — larger images and potential secret leakage.
101+
102+
### M14 — Dependabot Only Covers GitHub Actions
103+
**File:** `.github/dependabot.yml` — only `github-actions` ecosystem monitored. `npm`, `pip`, and `nuget` packages are unmonitored for CVEs.
104+
105+
---
106+
107+
## LOW
108+
109+
### L1 — Hardcoded Service Hostnames
110+
`result/server.js:21` and `worker/Program.cs:19` hardcode the hostname `db`. These are not configurable via environment variables, making multi-environment deployments fragile.
111+
112+
### L2 — `nodemon` in Production Result Image
113+
**File:** `result/Dockerfile:11` — `nodemon` installed globally in the production image. Development tool adds unnecessary attack surface.
114+
115+
### L3 — Git Short SHA as Image Tag
116+
**File:** `Jenkinsfile:22-26` — 7-character short SHAs have collision risk in large repos and are not immutable identifiers for production traceability.
117+
118+
### L4 — Single Replica for All Kubernetes Deployments
119+
All `k8s-specifications/*-deployment.yaml` set `replicas: 1`. Any pod failure causes downtime. Vote and Result services should be at ≥2.
120+
121+
### L5 — No Kubernetes Namespace
122+
All K8s specs deploy to `default` namespace — no isolation, no RBAC scoping possible.
123+
124+
### L6 — `chmod +x` on Every Pipeline Run
125+
**File:** `Jenkinsfile` — scripts have `chmod +x` applied each run rather than committing the executable bit with `git update-index --chmod=+x`.
126+
127+
### L7 — Redis and PostgreSQL Are Single Points of Failure
128+
Both have no clustering, no replication, no backup strategy. Disk failure = data loss.
129+
130+
### L8 — No Observability Stack
131+
No log aggregation, no metrics (Prometheus), no alerting, no distributed tracing. Failures will go undetected until users report them.
132+
133+
---
134+
135+
## Summary
136+
137+
| Severity | Count |
138+
|----------|-------|
139+
| Critical | 5 |
140+
| Medium | 14 |
141+
| Low | 8 |
142+
143+
**Top priority fixes in order:**
144+
1. Add `const path = require('path')` to `result/server.js` — service is currently broken
145+
2. Remove hardcoded DB credentials, inject via env vars
146+
3. Replace `emptyDir` with `PersistentVolumeClaim` for Postgres in K8s
147+
4. Remove `|| true` from all Jenkins pipeline steps
148+
5. Remove Docker socket mount from Trivy container
149+
6. Set `debug=False` in `vote/app.py` and switch to gunicorn

0 commit comments

Comments
 (0)