Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,67 @@ jobs:
type=sha,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}

# Test the same minimal HTTP-only Docker application; no TLS setup is added.
- name: Build fresh Docker image for security testing
run: docker build --pull -t markdown-viewer:security-audit .

- name: Smoke-test HTTP application and Nginx configuration
run: |
docker run -d --rm --name mdv-security-test -p 127.0.0.1:18080:80 markdown-viewer:security-audit
trap 'docker stop mdv-security-test >/dev/null 2>&1 || true' EXIT
docker exec mdv-security-test nginx -t
for i in $(seq 1 30); do
if curl -fsS --max-time 3 -o /dev/null http://127.0.0.1:18080/; then break; fi
sleep 1
done
curl -fsS --max-time 10 -o /dev/null http://127.0.0.1:18080/
curl -fsS --max-time 10 -o /dev/null http://127.0.0.1:18080/styles.css
curl -fsS --max-time 10 -o /dev/null http://127.0.0.1:18080/script.js
curl -fsSI --max-time 10 http://127.0.0.1:18080/ | grep -qi '^content-security-policy:'
! curl -fsSI --max-time 10 http://127.0.0.1:18080/ | grep -qi 'upgrade-insecure-requests'

- name: Prepare Docker vulnerability report directory
run: mkdir -p docker-artifacts

- name: Scan all known OS and library CVEs (machine-readable artifact)
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: markdown-viewer:security-audit
format: json
output: docker-artifacts/trivy-vulnerabilities.json
scanners: vuln
vuln-type: os,library
severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL
exit-code: '0'

- name: Fail on fixable critical or high vulnerabilities
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: markdown-viewer:security-audit
format: table
scanners: vuln
vuln-type: os,library
severity: CRITICAL,HIGH
ignore-unfixed: true
exit-code: '1'

- name: Upload complete vulnerability scan report
if: always()
uses: actions/upload-artifact@v4
with:
name: docker-security-report
path: docker-artifacts/trivy-vulnerabilities.json
if-no-files-found: ignore

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
pull: true
# Registry-published images carry provenance and an SBOM attestation.
# Local Docker image-store scans do not inherit registry attestations.
provenance: mode=max
sbom: true
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Use nginx as the base image for serving static files
FROM nginx:alpine
FROM nginx:1.31.8-alpine3.24-slim

# Omit optional Alpine/Nginx modules to reduce third-party package exposure.
# Apply security updates from the supported Alpine stable release.
RUN apk upgrade --no-cache

# PERF-019: Only copy necessary web files (exclude .git, desktop-app, wiki, etc.)
COPY index.html /usr/share/nginx/html/
Expand Down
Loading