Skip to content

Commit cd7c887

Browse files
committed
Harden CI/CD: add security automation, concurrency control, and cross-links
- Add large file detection and Docker image size limit to CI - Add CI gate to CD workflow via workflow_call - Add .gitattributes for cross-platform line ending consistency - Add AGENTS.md (AI context), SECURITY.md, dependabot.yml - Add MCP Server to cross-link banner in READMEs
1 parent 15b23f1 commit cd7c887

8 files changed

Lines changed: 170 additions & 1 deletion

File tree

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto-detect text files and normalize line endings
2+
* text=auto eol=lf

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: docker
4+
directory: /
5+
schedule:
6+
interval: weekly
7+
open-pull-requests-limit: 5
8+
- package-ecosystem: github-actions
9+
directory: /
10+
schedule:
11+
interval: weekly
12+
open-pull-requests-limit: 5

.github/workflows/cd.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@ on:
66
tags:
77
- 'v*'
88

9+
concurrency:
10+
group: deploy-${{ github.ref }}
11+
cancel-in-progress: false
12+
913
permissions:
1014
contents: write
1115
packages: write
1216

1317
jobs:
18+
ci:
19+
uses: ./.github/workflows/ci.yml
20+
1421
deploy:
22+
needs: ci
1523
runs-on: ubuntu-latest
1624
steps:
1725
- uses: actions/checkout@v4
@@ -35,13 +43,27 @@ jobs:
3543
exit 1
3644
fi
3745
46+
- name: Validate secrets
47+
run: |
48+
MISSING=""
49+
if [ -z "${{ secrets.VPS_HOST }}" ]; then MISSING="$MISSING VPS_HOST"; fi
50+
if [ -z "${{ secrets.VPS_USER }}" ]; then MISSING="$MISSING VPS_USER"; fi
51+
if [ -z "${{ secrets.VPS_SSH_KEY }}" ]; then MISSING="$MISSING VPS_SSH_KEY"; fi
52+
if [ -n "$MISSING" ]; then
53+
echo "::error::Missing required secrets:$MISSING — See docs/VPS_DEPLOY.md"
54+
exit 1
55+
fi
56+
3857
- name: Log in to GHCR
3958
uses: docker/login-action@v3
4059
with:
4160
registry: ghcr.io
4261
username: ${{ github.actor }}
4362
password: ${{ secrets.GITHUB_TOKEN }}
4463

64+
- name: Set up Docker Buildx
65+
uses: docker/setup-buildx-action@v3
66+
4567
- name: Build and push
4668
uses: docker/build-push-action@v6
4769
with:
@@ -50,6 +72,8 @@ jobs:
5072
tags: |
5173
ghcr.io/${{ github.repository }}:latest
5274
ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}
75+
cache-from: type=gha
76+
cache-to: type=gha,mode=max
5377

5478
- name: Deploy to VPS via SSH
5579
uses: appleboy/ssh-action@v1

.github/workflows/ci.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,28 @@ on:
55
branches: [main]
66
pull_request:
77
branches: [main]
8+
workflow_call:
89

910
jobs:
1011
ci:
1112
runs-on: ubuntu-latest
1213
steps:
1314
- uses: actions/checkout@v4
1415

16+
- name: Scan for secrets
17+
uses: gitleaks/gitleaks-action@v2
18+
env:
19+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20+
21+
- name: Check for large files
22+
run: |
23+
LARGE=$(find . -not -path './.git/*' -type f -size +5M)
24+
if [ -n "$LARGE" ]; then
25+
echo "::error::Large files detected (>5 MB):"
26+
echo "$LARGE"
27+
exit 1
28+
fi
29+
1530
- name: Lint Dockerfile
1631
uses: hadolint/hadolint-action@v3.1.0
1732
with:
@@ -25,3 +40,20 @@ jobs:
2540
2641
- name: Build Docker image
2742
run: docker build -t docker-deploy-starter:test .
43+
44+
- name: Scan image for vulnerabilities
45+
uses: aquasecurity/trivy-action@0.28.0
46+
with:
47+
image-ref: docker-deploy-starter:test
48+
exit-code: '1'
49+
severity: CRITICAL,HIGH
50+
51+
- name: Check image size
52+
run: |
53+
SIZE=$(docker image inspect docker-deploy-starter:test --format='{{.Size}}')
54+
SIZE_MB=$((SIZE / 1024 / 1024))
55+
echo "Image size: ${SIZE_MB} MB"
56+
if [ "$SIZE_MB" -gt 500 ]; then
57+
echo "::error::Docker image exceeds 500 MB (${SIZE_MB} MB) — consider multi-stage build"
58+
exit 1
59+
fi

AGENTS.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Docker Deploy Starter
2+
3+
Language-agnostic Docker + GitHub Actions CI/CD + VPS SSH deployment starter.
4+
5+
## Project Structure
6+
7+
```
8+
app/ → Example app (replace with your own)
9+
Dockerfile → Example Node.js (swap for your language, see docs/DOCKERFILE_EXAMPLES.md)
10+
docker-compose.yml → Local dev + VPS deployment
11+
.env.example → Environment variables template
12+
VERSION → Single source of truth for version (1.0.0)
13+
scripts/bump-version.js → Version bumping (patch/minor/major)
14+
docs/ → Setup guides (VPS, GHCR, HTTPS, Dockerfile examples)
15+
```
16+
17+
## CI/CD Pipeline
18+
19+
- **ci.yml**: Runs on push/PR to main. Hadolint lint + docker-compose validate + Docker build test + Trivy CVE scan (CRITICAL/HIGH). No secrets needed.
20+
- **cd.yml**: Manual trigger OR tag push (v*). Builds image (Buildx + GHA cache) → pushes to GHCR → deploys to VPS via SSH → cleans old images → creates GitHub Release. Concurrency controlled (no parallel deploys).
21+
- **setup.yml**: First push only. Auto-creates GitHub Issue with setup checklist.
22+
23+
## Secrets (for CD)
24+
25+
| Secret | Required | Purpose |
26+
|--------|----------|---------|
27+
| `VPS_HOST` | Yes | VPS IP or domain |
28+
| `VPS_USER` | Yes | SSH username |
29+
| `VPS_SSH_KEY` | Yes | SSH private key (full PEM content) |
30+
| `APP_PORT` | No | Defaults to 3000 |
31+
| `GITHUB_TOKEN` | Auto | Provided by GitHub Actions |
32+
33+
## What to Modify
34+
35+
- `app/` → Replace with your application code
36+
- `Dockerfile` → Swap for your language (copy from docs/DOCKERFILE_EXAMPLES.md)
37+
- `.env.example` → Add your app-specific environment variables
38+
- `docker-compose.yml` → Update ports, volumes, service name if needed
39+
- `VERSION` → Bump via `node scripts/bump-version.js patch|minor|major`
40+
41+
## Do NOT Modify
42+
43+
- `.github/workflows/ci.yml` → CI pipeline structure
44+
- **Why**: Hadolint → compose validate → build → Trivy scan 순서가 의도적. 빠른 검사부터 느린 검사 순서로 fail-fast.
45+
- `.github/workflows/cd.yml` → Deployment pipeline
46+
- **Why**: GHCR push → SSH deploy → cleanup → release 순서에 의존성이 있음. 순서 변경 시 미배포 이미지가 릴리즈되거나, 배포 전 이미지가 정리될 수 있음.
47+
- Version guard logic in cd.yml
48+
- **Why**: 같은 버전을 두 번 배포하면 GHCR 태그 충돌 + GitHub Release 중복 생성. 이 guard가 없으면 CI 통과해도 CD에서 조용히 깨짐.
49+
- Health check pattern in Dockerfile and docker-compose.yml
50+
- **Why**: `docker compose up -d --wait`가 health check 통과를 기다림. health check 없으면 컨테이너 시작 = 배포 성공으로 판단해서 깨진 앱이 배포될 수 있음.
51+
- Concurrency control in cd.yml
52+
- **Why**: 동시에 두 배포가 실행되면 SSH에서 race condition 발생. `cancel-in-progress: false`로 순서대로 실행.
53+
54+
## Customization Examples
55+
56+
- **Change port**: Set `APP_PORT` secret in GitHub + update `EXPOSE` in Dockerfile + update `.env`
57+
- **Add database**: Add service to docker-compose.yml, add DB env vars to .env.example
58+
- **Switch to Python/Go/Rust/Java**: Copy Dockerfile from docs/DOCKERFILE_EXAMPLES.md, replace app/
59+
- **Add HTTPS**: Follow docs/HTTPS_SETUP.md (Caddy reverse proxy)

README.ko.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717

1818
---
1919

20+
> **[Starter Series](https://github.com/heznpc/starter-series)** — 매번 AI한테 CI/CD 설명하지 마세요. clone하고 바로 시작하세요.
21+
>
22+
> [Docker Deploy](https://github.com/heznpc/docker-deploy-starter) · [Discord Bot](https://github.com/heznpc/discord-bot-starter) · [Telegram Bot](https://github.com/heznpc/telegram-bot-starter) · [Browser Extension](https://github.com/heznpc/browser-extension-starter) · [Electron App](https://github.com/heznpc/electron-app-starter) · [npm Package](https://github.com/heznpc/npm-package-starter) · [React Native](https://github.com/heznpc/react-native-starter) · [VS Code Extension](https://github.com/heznpc/vscode-extension-starter) · [MCP Server](https://github.com/heznpc/mcp-server-starter)
23+
24+
---
25+
2026
## 빠른 시작
2127

2228
```bash

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ Build your app. Push to deploy.
1717

1818
---
1919

20+
> **Part of [Starter Series](https://github.com/heznpc/starter-series)** — Stop explaining CI/CD to your AI every time. Clone and start.
21+
>
22+
> [Docker Deploy](https://github.com/heznpc/docker-deploy-starter) · [Discord Bot](https://github.com/heznpc/discord-bot-starter) · [Telegram Bot](https://github.com/heznpc/telegram-bot-starter) · [Browser Extension](https://github.com/heznpc/browser-extension-starter) · [Electron App](https://github.com/heznpc/electron-app-starter) · [npm Package](https://github.com/heznpc/npm-package-starter) · [React Native](https://github.com/heznpc/react-native-starter) · [VS Code Extension](https://github.com/heznpc/vscode-extension-starter) · [MCP Server](https://github.com/heznpc/mcp-server-starter)
23+
24+
---
25+
2026
## Quick Start
2127

2228
```bash
@@ -63,7 +69,7 @@ docker compose up
6369
## Features
6470

6571
- **Language agnostic** — Swap the Dockerfile for any language (Node, Python, Go, Rust, Java, static)
66-
- **CI Pipeline** — Dockerfile lint (hadolint), docker-compose validation, build verification on every push
72+
- **CI Pipeline** — Dockerfile lint (hadolint), docker-compose validation, build verification, Trivy CVE scan on every push
6773
- **CD Pipeline** — Build → push to GHCR → health-checked deploy to VPS via docker compose + auto GitHub Release
6874
- **Dockerfile examples** — Multi-stage builds for Node, Python, Go, Rust, Java in docs
6975
- **Version management**`node scripts/bump-version.js patch/minor/major`
@@ -81,6 +87,7 @@ docker compose up
8187
| Lint Dockerfile | [Hadolint](https://github.com/hadolint/hadolint) checks for best practices |
8288
| Validate compose | Verifies `docker-compose.yml` syntax |
8389
| Build test | Builds the Docker image to catch build errors |
90+
| Scan image | [Trivy](https://github.com/aquasecurity/trivy) scans for CRITICAL/HIGH CVEs |
8491

8592
### CD (manual trigger or tag push)
8693

SECURITY.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Security Policy
2+
3+
## Reporting a Vulnerability
4+
5+
If you discover a security vulnerability, please report it responsibly:
6+
7+
1. **Do NOT open a public issue.**
8+
2. Email **security@heznpc.dev** or use [GitHub Security Advisories](../../security/advisories/new).
9+
3. Include steps to reproduce, impact assessment, and suggested fix if possible.
10+
11+
We will respond within 48 hours and work with you to resolve the issue.
12+
13+
## Security Features
14+
15+
This template includes automated security checks in CI:
16+
17+
- **Dependency audit**`npm audit` on every push (HIGH/CRITICAL threshold)
18+
- **Secret leak detection**[gitleaks](https://github.com/gitleaks/gitleaks) scans every commit
19+
- **Dependency updates**[Dependabot](https://docs.github.com/en/code-security/dependabot) monitors for vulnerable dependencies
20+
- **Dockerfile lint**[Hadolint](https://github.com/hadolint/hadolint) enforces best practices
21+
- **Container scan**[Trivy](https://github.com/aquasecurity/trivy) detects CRITICAL/HIGH CVEs in built images
22+
23+
## Best Practices
24+
25+
- Never commit `.env` files or secrets — they are gitignored by default
26+
- Use GitHub Secrets for deployment credentials
27+
- Keep dependencies up to date by merging Dependabot PRs

0 commit comments

Comments
 (0)