This commit is contained in:
Johan
2026-02-04 11:52:22 +01:00
parent d6f1cd0360
commit 0004fa1895
5 changed files with 201 additions and 4 deletions

View File

@@ -55,3 +55,90 @@ jobs:
- name: Run tests - name: Run tests
run: | run: |
if [ -d backend/tests ]; then pytest -q; else echo "No tests found"; fi if [ -d backend/tests ]; then pytest -q; else echo "No tests found"; fi
docker-lint:
name: Docker Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run Hadolint on backend Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: backend/Dockerfile
ignore: DL3045
- name: Run Hadolint on frontend Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: frontend/Dockerfile
ignore: DL3045
build-and-scan:
name: Build and Scan Docker Images
needs: docker-lint
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build backend image
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
push: false
load: true
tags: backend:latest
- name: Build frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
push: false
load: true
tags: frontend:latest
- name: Scan backend with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: backend:latest
format: sarif
output: backend-trivy.sarif
- name: Scan frontend with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: frontend:latest
format: sarif
output: frontend-trivy.sarif
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: backend-trivy.sarif
- name: Upload frontend Trivy results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: frontend-trivy.sarif
validate-docker-compose:
name: Validate Docker Compose
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Validate docker-compose.yml
run: |
docker-compose -f docker-compose.yml config > /dev/null
continue-on-error: true

BIN
atelier02-conteneurisation.pdf Executable file

Binary file not shown.

View File

@@ -1,9 +1,27 @@
FROM python:3.12 # Stage 1: Tests et qualité
FROM python:3.12 as test
WORKDIR /app WORKDIR /app
COPY . /app/ COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt flake8 bandit
RUN pip install -r requirements.txt COPY . .
# Tests de qualité
RUN flake8 app/ --count --show-source --statistics || true
RUN bandit -r app/ -f json -o /tmp/bandit-report.json || true
# Stage 2: Application runtime
FROM python:3.12-slim as runtime
WORKDIR /app
# Non-root user pour la sécurité
RUN useradd -m -u 1000 appuser
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --from=test /app .
RUN chown -R appuser:appuser /app
USER appuser
EXPOSE 8000 EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

50
docker-compose.yml Normal file
View File

@@ -0,0 +1,50 @@
version: '3.9'
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
target: runtime
container_name: eni-backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=sqlite:///./test.db
volumes:
- ./backend/app:/app/app
restart: unless-stopped
networks:
- eni-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
interval: 10s
timeout: 5s
retries: 5
start_period: 5s
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: eni-frontend
ports:
- "80:80"
environment:
- API_URL=http://backend:8000
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
networks:
- eni-network
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
interval: 10s
timeout: 5s
retries: 5
start_period: 5s
networks:
eni-network:
driver: bridge

42
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,42 @@
# Stage 1: Build
FROM node:20-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm install || true
COPY . .
# Aucun build nécessaire pour cette app vanilla JS
# mais on peut valider la qualité du code
RUN npm run lint 2>/dev/null || echo "No lint script"
# Stage 2: Runtime avec nginx
FROM nginx:alpine-slim
WORKDIR /usr/share/nginx/html
# Copier les fichiers depuis le stage builder
COPY --from=builder /app .
# Copier une configuration nginx pour le SPA
RUN cat > /etc/nginx/conf.d/default.conf << 'EOF'
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Cache les assets statiques
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Fallback pour le SPA
location / {
try_files $uri /index.html;
}
}
EOF
USER nginx:nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]