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
106 changes: 21 additions & 85 deletions .github/workflows/cart.yaml
Original file line number Diff line number Diff line change
@@ -1,100 +1,41 @@
# ==============================================================
# Jerney - DevSecOps CI/CD Pipeline
# ==============================================================
# Triggers on every push and pull request.
# Stages: Lint β†’ SCA β†’ Build β†’ Image Scan β†’ IaC Scan β†’ Deploy Manifest Update
# Shopstack - DevSecOps CI/CD Pipeline
# ==============================================================

name: Jerney DevSecOps Pipeline
name: Shopstack DevSecOps Pipeline

on:
push:
branches: ["*"]
branches:
- env/prod
paths:
- "cart/**"
- ".github/workflows/cart.yaml"
pull_request:
branches: ["*"]
branches:
- env/prod
paths:
- "cart/**"
- ".github/workflows/cart.yaml"

# Security: restrict default permissions to read-only
permissions:
contents: read

env:
DOCKER_REGISTRY: ghcr.io
BACKEND_IMAGE: ghcr.io/${{ github.repository }}/jerney-backend
FRONTEND_IMAGE: ghcr.io/${{ github.repository }}/jerney-frontend
PROJECT: "shopstack"
ENV: "staging"

jobs:
# ==============================================================
# STAGE 1: Linting
# ==============================================================
lint:
name: "πŸ” Lint Code"
runs-on: ubuntu-latest
strategy:
matrix:
component: [backend, frontend]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: "${{ matrix.component }}/package-lock.json"

- name: Install dependencies
working-directory: ${{ matrix.component }}
run: npm ci

- name: Run ESLint
working-directory: ${{ matrix.component }}
run: npm run lint

# ==============================================================
# STAGE 2: Software Composition Analysis (SCA) β€” Dependency Audit
# ==============================================================
sca:
name: "πŸ›‘οΈ Dependency Audit"
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
component: [backend, frontend]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: "${{ matrix.component }}/package-lock.json"

- name: Install dependencies
working-directory: ${{ matrix.component }}
run: npm ci

# npm audit for known vulnerabilities (fail on high/critical)
- name: npm audit
working-directory: ${{ matrix.component }}
run: npm audit --audit-level=high || true
# `|| true` to not fail on moderate β€” adjust in prod

# ==============================================================
# STAGE 3: Build & Push Container Images
# ==============================================================
build:
name: "🐳 Build ${{ matrix.component }}"
runs-on: ubuntu-latest
needs: sca
permissions:
contents: read
packages: write # Needed to push to GHCR
strategy:
matrix:
component: [backend, frontend]
component: ["cart"]
outputs:
image_tag: ${{ steps.meta.outputs.version }}
steps:
Expand All @@ -115,7 +56,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}/jerney-${{ matrix.component }}
images: ghcr.io/${{ github.repository_owner }}/${{ env.ENV }}/${{ env.PROJECT }}-${{ matrix.component }}
tags: |
type=sha,prefix=
type=ref,event=branch
Expand All @@ -135,44 +76,39 @@ jobs:
provenance: true
sbom: true

# ==============================================================
# STAGE 4: Container Image Scanning (Trivy)
# ==============================================================

image-scan:
name: "πŸ”¬ Scan ${{ matrix.component }} Image"
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
component: [backend, frontend]
component: ["cart"]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Build image for scanning
run: |
docker build -t jerney-${{ matrix.component }}:scan ./${{ matrix.component }}
docker build -t ${{ env.PROJECT }}-${{ matrix.component }}:scan ./${{ matrix.component }}

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: "jerney-${{ matrix.component }}:scan"
image-ref: "${{ env.PROJECT }}-${{ matrix.component }}:scan"
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
timeout: "10m"

# ==============================================================
# STAGE 6: Dockerfile Lint (Hadolint)
# ==============================================================
dockerfile-lint:
name: "πŸ“‹ Dockerfile Lint"
runs-on: ubuntu-latest
strategy:
matrix:
component: [backend, frontend]
component: ["cart"]
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down
120 changes: 120 additions & 0 deletions .github/workflows/catalogue.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# ==============================================================
# Shopstack - DevSecOps CI/CD Pipeline
# ==============================================================

name: Shopstack DevSecOps Pipeline

on:
push:
branches:
- env/prod
paths:
- "catalogue/**"
- ".github/workflows/catalogue.yaml"
pull_request:
branches:
- env/prod
paths:
- "catalogue/**"
- ".github/workflows/catalogue.yaml"

# Security: restrict default permissions to read-only
permissions:
contents: read

env:
PROJECT: "shopstack"
ENV: "staging"

jobs:
build:
name: "🐳 Build ${{ matrix.component }}"
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # Needed to push to GHCR
strategy:
matrix:
component: ["catalogue"]
outputs:
image_tag: ${{ steps.meta.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- 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: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/${{ env.ENV }}/${{ env.PROJECT }}-${{ matrix.component }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: ./${{ matrix.component }}
file: ./${{ matrix.component }}/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Security: provenance and SBOM
provenance: true
sbom: true


image-scan:
name: "πŸ”¬ Scan ${{ matrix.component }} Image"
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
component: ["catalogue"]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Build image for scanning
run: |
docker build -t ${{ env.PROJECT }}-${{ matrix.component }}:scan ./${{ matrix.component }}

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: "${{ env.PROJECT }}-${{ matrix.component }}:scan"
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
timeout: "10m"

dockerfile-lint:
name: "πŸ“‹ Dockerfile Lint"
runs-on: ubuntu-latest
strategy:
matrix:
component: ["catalogue"]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: ${{ matrix.component }}/Dockerfile
failure-threshold: warning
Loading
Loading