Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Bash(node:*)",
"Bash(npm run:*)",
"Bash(npm test:*)",
"Bash(ls:*)"
"Bash(ls:*)",
"Bash(chmod +x:*)"
]
}
}
87 changes: 87 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
version: 2

updates:
# ─── npm dependencies ───────────────────────────────────────────────
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: '06:00'
timezone: America/Sao_Paulo
open-pull-requests-limit: 10
groups:
nestjs-core:
patterns:
- '@nestjs/*'
update-types:
- minor
- patch
security-deps:
patterns:
- 'argon2'
- 'helmet'
- 'passport*'
- 'jsonwebtoken'
- '@nestjs/jwt'
- 'express-rate-limit'
update-types:
- minor
- patch
drizzle:
patterns:
- 'drizzle-orm'
- 'drizzle-kit'
update-types:
- minor
- patch
dev-tools:
patterns:
- 'eslint*'
- '@typescript-eslint/*'
- 'prettier'
- 'jest'
- 'ts-jest'
- 'husky'
- '@commitlint/*'
update-types:
- minor
- patch
labels:
- 'dependencies'
- 'automated'
commit-message:
prefix: 'chore(deps)'
include: scope

# ─── GitHub Actions ──────────────────────────────────────────────────
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: '06:00'
timezone: America/Sao_Paulo
open-pull-requests-limit: 5
labels:
- 'dependencies'
- 'github-actions'
- 'automated'
commit-message:
prefix: 'chore(ci)'

# ─── Docker ──────────────────────────────────────────────────────────
- package-ecosystem: docker
directory: /
schedule:
interval: weekly
day: monday
time: '06:00'
timezone: America/Sao_Paulo
open-pull-requests-limit: 3
labels:
- 'dependencies'
- 'docker'
- 'automated'
commit-message:
prefix: 'chore(docker)'
82 changes: 82 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: CD

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
release:
name: Build & Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
id-token: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU (multi-arch)
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata (tags + labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix=sha-,format=short
labels: |
org.opencontainers.image.title=NestJS Security Pro
org.opencontainers.image.description=Production-grade NestJS + Drizzle ORM template with enterprise security
org.opencontainers.image.vendor=Ramos de Souza Janones

- name: Build and push multi-arch image (linux/amd64 + linux/arm64)
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Create GitHub Release with changelog
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
body: |
## Docker Image

```bash
docker pull ghcr.io/${{ github.repository }}:${{ github.ref_name }}
```

### Platforms
- `linux/amd64`
- `linux/arm64`

---
Auto-generated by CD pipeline · Commit: `${{ github.sha }}`
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
177 changes: 177 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
name: CI

on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
NODE_VERSION: '22'

jobs:
# ─────────────────────────────────────────────
# Job 1: Lint + Type-check
# ─────────────────────────────────────────────
lint-typecheck:
name: Lint & Type-check
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: ESLint + Prettier check
run: npm run ci:lint

- name: TypeScript type-check
run: npm run type-check

# ─────────────────────────────────────────────
# Job 2: Unit tests + coverage ≥ 85%
# ─────────────────────────────────────────────
test:
name: Tests (coverage ≥ 85%)
runs-on: ubuntu-latest
needs: lint-typecheck

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Generate RSA test keys
run: |
openssl genrsa -out /tmp/test-private.pem 2048
openssl rsa -in /tmp/test-private.pem -pubout -out /tmp/test-public.pem
{
echo "PRIVATE_KEY<<CI_KEY_EOF"
cat /tmp/test-private.pem
echo "CI_KEY_EOF"
} >> "$GITHUB_ENV"
{
echo "PUBLIC_KEY<<CI_PUB_EOF"
cat /tmp/test-public.pem
echo "CI_PUB_EOF"
} >> "$GITHUB_ENV"

- name: Run tests with 85% coverage threshold
run: |
npx jest --coverage \
--coverageThreshold='{"global":{"statements":85,"branches":85,"functions":85,"lines":85}}' \
--forceExit
env:
NODE_ENV: test
DB_HOST: localhost
DB_PORT: 5432
DB_USERNAME: postgres
DB_PASSWORD: postgres
DB_DATABASE: testdb
REDIS_HOST: localhost
REDIS_PORT: 6379
DISABLE_REDIS: 'true'

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./coverage
fail_ci_if_error: false

# ─────────────────────────────────────────────
# Job 3: npm audit (falha em high/critical)
# ─────────────────────────────────────────────
audit:
name: Security Audit
runs-on: ubuntu-latest
needs: lint-typecheck

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: npm audit (high/critical → fail)
run: npm audit --audit-level=high

# ─────────────────────────────────────────────
# Job 4: Build TypeScript + Docker + Trivy scan
# ─────────────────────────────────────────────
build:
name: Build & Docker Scan
runs-on: ubuntu-latest
needs: [test, audit]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build TypeScript (nest build)
run: npm run build

- name: Drizzle schema sanity-check
run: npx drizzle-kit check
continue-on-error: true
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
load: true
tags: app-ci:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Scan Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'app-ci:${{ github.sha }}'
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
Loading
Loading