-
Notifications
You must be signed in to change notification settings - Fork 8
feat(docker): image nginx + publication GHCR sur tag #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
a9faa8d
feat(docker): nginx image serving the SPA, GHCR publish on tag
sebdraven 681d79d
ci(docker): :latest tracks main, :vX.Y.Z published on tag push
sebdraven b432e8e
feat(docker): publish a sibling test image runnable with pytest
sebdraven 4bb20e3
fix(docker): address Copilot review and standardise on uv
sebdraven befbfb9
fix(docker): lockfile-frozen tests image and broader PR path filter
sebdraven File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Git | ||
| .git/ | ||
| .gitignore | ||
| .gitattributes | ||
|
|
||
| # CI / IDE / harness metadata | ||
| .github/ | ||
| .vscode/ | ||
| .idea/ | ||
| .claude/ | ||
|
|
||
| # Python / uv caches and virtualenvs | ||
| .venv/ | ||
| __pycache__/ | ||
| *.py[cod] | ||
| *$py.class | ||
| .pytest_cache/ | ||
| .mypy_cache/ | ||
| .ruff_cache/ | ||
| .coverage | ||
| htmlcov/ | ||
|
|
||
| # Large or unrelated repo content | ||
| DIMA_V7.pdf | ||
| article/ | ||
| plugin/ | ||
| misp/ | ||
|
|
||
| # Docs & licensing not needed at build time | ||
| README.md | ||
| LICENSE | ||
|
|
||
| # Test outputs | ||
| _regen_misp/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| name: Docker image | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| tags: ["v*"] | ||
| pull_request: | ||
| paths: | ||
| - "docker/**" | ||
| - ".github/workflows/docker.yml" | ||
| - "src/**" | ||
|
sebdraven marked this conversation as resolved.
|
||
| - "docs/**" | ||
| - "DETECT/**" | ||
| - "INFORM/**" | ||
| - "MEMORISE/**" | ||
| - "ACT/**" | ||
| - "pyproject.toml" | ||
| - "uv.lock" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: write | ||
|
|
||
| env: | ||
| REGISTRY: ghcr.io | ||
| IMAGE_NAME: ${{ github.repository }} | ||
|
|
||
| jobs: | ||
| runtime: | ||
| name: Runtime image (nginx) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up QEMU | ||
| uses: docker/setup-qemu-action@v3 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Log in to GHCR | ||
| if: github.event_name != 'pull_request' | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
| tags: | | ||
| type=ref,event=tag | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
| type=sha,prefix=sha-,enable=${{ github.event_name == 'workflow_dispatch' }} | ||
|
sebdraven marked this conversation as resolved.
|
||
|
|
||
|
sebdraven marked this conversation as resolved.
|
||
| - name: Build (and push on tag or main) | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| file: docker/Dockerfile | ||
| target: runtime | ||
|
sebdraven marked this conversation as resolved.
|
||
| platforms: linux/amd64,linux/arm64 | ||
| push: ${{ github.event_name != 'pull_request' && steps.meta.outputs.tags != '' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
|
sebdraven marked this conversation as resolved.
|
||
| cache-from: type=gha,scope=runtime | ||
| cache-to: type=gha,mode=max,scope=runtime | ||
|
|
||
| tests: | ||
| name: Test image (pytest) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Log in to GHCR | ||
| if: github.event_name != 'pull_request' | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
| flavor: suffix=-tests,onlatest=true | ||
| tags: | | ||
| type=ref,event=tag | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
| type=sha,prefix=sha-,enable=${{ github.event_name == 'workflow_dispatch' }} | ||
|
|
||
| - name: Build (linux/amd64 only) and push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| file: docker/Dockerfile | ||
| target: tests | ||
| platforms: linux/amd64 | ||
| push: ${{ github.event_name != 'pull_request' && steps.meta.outputs.tags != '' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
|
sebdraven marked this conversation as resolved.
|
||
| cache-from: type=gha,scope=tests | ||
| cache-to: type=gha,mode=max,scope=tests | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,6 @@ env/ | |
|
|
||
| # uv | ||
| .uv/ | ||
| uv.lock | ||
|
|
||
| # Tests / outils | ||
| .pytest_cache/ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # syntax=docker/dockerfile:1.6 | ||
|
|
||
| # ---- Stage 1: regenerate the per-phase JSONs from the Markdown sources ---- | ||
| # Uses the official uv image (Python 3.12 on Alpine) so the same toolchain | ||
| # is used in every stage. The converter itself depends on stdlib only, | ||
| # so we invoke python directly via `uv run --no-project`. | ||
| FROM ghcr.io/astral-sh/uv:python3.12-alpine AS builder | ||
| WORKDIR /build | ||
|
|
||
| COPY src/dima_convert.py ./src/dima_convert.py | ||
| COPY DETECT/ ./DETECT/ | ||
| COPY INFORM/ ./INFORM/ | ||
| COPY MEMORISE/ ./MEMORISE/ | ||
| COPY ACT/ ./ACT/ | ||
| COPY docs/ ./docs/ | ||
|
|
||
| RUN uv run --no-project python src/dima_convert.py md2json --all -o docs/data | ||
|
|
||
| # ---- Stage 2: pytest runner (build standalone with --target tests) ---- | ||
| # Pytest version comes from pyproject.toml's [dependency-groups].dev, | ||
| # so the build stays reproducible (no implicit pytest latest). | ||
| FROM ghcr.io/astral-sh/uv:python3.12-alpine AS tests | ||
| WORKDIR /app | ||
|
|
||
| COPY pyproject.toml uv.lock ./ | ||
| COPY src/ ./src/ | ||
| COPY DETECT/ ./DETECT/ | ||
| COPY INFORM/ ./INFORM/ | ||
| COPY MEMORISE/ ./MEMORISE/ | ||
| COPY ACT/ ./ACT/ | ||
|
|
||
| # Synchronise the dev group (pytest) into /app/.venv with the exact | ||
| # versions resolved in uv.lock (--frozen). The image is reproducible: | ||
| # rebuilding from the same commit always pulls the same pytest. | ||
| RUN uv sync --group dev --frozen | ||
|
|
||
| # Run the suite at build time so `docker build --target tests` fails on regression. | ||
| RUN uv run pytest | ||
|
|
||
| # And keep the same entrypoint for interactive runs (docker run --rm <image>). | ||
| CMD ["uv", "run", "pytest", "-v"] | ||
|
|
||
| # ---- Stage 3: nginx runtime (default target) ---- | ||
| FROM nginxinc/nginx-unprivileged:alpine AS runtime | ||
|
|
||
| LABEL org.opencontainers.image.title="DIMA Navigator" \ | ||
| org.opencontainers.image.description="Static SPA serving the DIMA matrix (Detect/Inform/Memorise/Act)." \ | ||
| org.opencontainers.image.source="https://github.com/M82-project/DIMA" \ | ||
| org.opencontainers.image.licenses="see repository" | ||
|
|
||
| COPY docker/nginx.conf /etc/nginx/conf.d/default.conf | ||
| COPY --from=builder /build/docs /usr/share/nginx/html | ||
|
|
||
| EXPOSE 8080 | ||
|
|
||
| HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ | ||
| CMD wget -qO- http://localhost:8080/ >/dev/null || exit 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| server { | ||
| listen 8080 default_server; | ||
| server_name _; | ||
|
|
||
| root /usr/share/nginx/html; | ||
| index index.html; | ||
|
|
||
| # Active la compression text/json/css/js | ||
| gzip on; | ||
| gzip_vary on; | ||
| gzip_min_length 256; | ||
| gzip_proxied any; | ||
| gzip_types | ||
| text/plain | ||
| text/css | ||
| text/javascript | ||
| application/javascript | ||
| application/json | ||
| image/svg+xml; | ||
|
|
||
| # HTML et JSON : pas de cache long, pour qu'un redeploiement | ||
| # se voie immediatement. | ||
| location ~* \.(html|json)$ { | ||
| add_header Cache-Control "no-cache, must-revalidate"; | ||
| try_files $uri =404; | ||
| } | ||
|
|
||
| # Assets versionnes (fonts, images) : cache long. | ||
| location ~* \.(woff2?|ttf|otf|png|jpg|jpeg|gif|webp|svg|ico)$ { | ||
| add_header Cache-Control "public, max-age=2592000, immutable"; | ||
| try_files $uri =404; | ||
| } | ||
|
|
||
| location / { | ||
|
sebdraven marked this conversation as resolved.
|
||
| try_files $uri $uri/ /index.html; | ||
| # Le fallback SPA sert /index.html sur des routes type /campaign/123 : | ||
| # comme la location regex ci-dessus ne matche pas (pas de .html dans | ||
| # l'URL), il faut redonner le no-cache ici pour que les redeploys | ||
| # soient visibles tout de suite. | ||
| add_header Cache-Control "no-cache, must-revalidate" always; | ||
| } | ||
|
|
||
| # Pas d'index automatique d'un repertoire sans index.html. | ||
| autoindex off; | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.