Compare commits

..

11 Commits

Author SHA1 Message Date
lebaudantoine c7b05a4487 ⚡️(devx) switch devstack to node:22-alpine
The devstack was pulling the full `node:22` image, around 1.6 GB.
Switch to `node:22-alpine`, which is much smaller, to speed up the
devstack bootstrap time and reduce disk usage.
2026-10-02 15:46:34 +02:00
lebaudantoine 971a7295ca ⚡️(devx) use a single Redis image version in the devstack
The devstack was pulling two different versions of the Redis image.
Align everything on a single version to save a few MB of network
bandwidth when bootstrapping the stack.

Late-night minor optimization.
2026-10-01 16:38:31 +02:00
lebaudantoine bd0329d162 🔒️(agents) upgrade libpcre2-8-0 to fix CVE-2026-103111
The python:3.14.7-slim base image ships libpcre2-8-0
10.46-1~deb13u2, which is affected by CVE-2026-103111 (HIGH):
an out-of-bounds write triggered by a crafted regular expression.

Explicitly install libpcre2-8-0 in the base stage so apt pulls
the patched 10.46-1~deb13u3 from trixie-security. All stages
(builder, development, production) inherit the fix.

This line can be dropped once an upstream python slim image
ships the patched package.
2026-10-01 16:37:29 +02:00
lebaudantoine cedaa32ab7 🔒️(backend) fix HIGH CVEs in Django and urllib3
Address the following HIGH severity CVEs reported by Trivy on the
backend image:

* Django 5.2.16 → 5.2.17
  - CVE-2026-15307 — remote code execution via GeoDjango spatial
    lookups.

* urllib3 2.7.0 → 2.8.0
  - CVE-2026-97687 — traffic interception via HTTPS proxy TLS
    configuration override.
  - CVE-2026-97689 — denial of service via unbounded memory
    allocation in the chunk parser.
2026-10-01 16:37:29 +02:00
lebaudantoine 22adccb353 👷(ci) ignore unfixed Debian CVEs in trivy scans
The trivy scan fails on HIGH vulnerabilities found in the Debian 13
base images (util-linux, acl, ncurses, systemd and perl-base). None
of them has a fixed version available yet, so there is nothing we
can upgrade to clear them.

List these CVEs in a shared .github/.trivyignore and pass it to
every image scan, so the scan stays blocking for any new HIGH or
CRITICAL vulnerability. Remove the entries once Debian ships a fix.
2026-10-01 00:13:36 +02:00
lebaudantoine 3ab651d6c7 👷(ci) pin the shared CI repo to v0.0.1
Instead of referencing the shared CI repo on `main`, pin it to the
initial tagged version `v0.0.1`, so the CI behavior is stable and
does not silently change when the shared repo is updated.
2026-10-01 00:13:36 +02:00
lebaudantoine 919af928aa 🚨(ci) fix the shellcheck job
Get the shellcheck CI job to pass again by addressing the issues it
flagged across our shell scripts.

Note: I am not 100% sure of every fix applied here. Reviewers should
feel free to challenge specific changes and suggest better ones
where relevant.
2026-10-01 00:13:36 +02:00
lebaudantoine 3ed38f1c48 🚨(ci) fix the spellcheck job
Get the spellcheck CI job to pass again by:

* Fixing the actual spelling issues it caught in the project.
* Excluding generated files from the scan, since they are not
  written by us.
* Excluding translation files, whose content is not necessarily in
  English and would trigger false positives.
2026-10-01 00:13:36 +02:00
lebaudantoine f172c5795e 👷(ci) add Menshen scan for GitHub Actions vulnerabilities
Wire Menshen into the CI to scan the GitHub Actions we use and flag
vulnerable ones, following the same approach as other projects that
recently adopted it.

Note: I am not fully sure about the current setup. Reviewers should
feel free to adjust the configuration or the integration point as
they see fit.
2026-10-01 00:13:36 +02:00
lebaudantoine 262b168414 🔥(ci) drop unused Crowdin workflows
The Crowdin workflows were not used by the project and had turned
into dead CI code.

Remove them to reduce noise and keep the CI configuration limited
to what is actually running.
2026-10-01 00:13:36 +02:00
lebaudantoine 6c371c8cb3 👷(ci) migrate CI to the shared workflows repository
First iteration of a migration toward a centralized repository
containing our shared CI logic.

Goals:

* Manage GitHub Actions version upgrades in one place.
* Make it easier to audit what actually runs in CI from a security
  perspective.
* Avoid duplicating CI logic across projects and having each
  repository slowly diverge over time.
* Centralize as many of our custom GitHub Actions as possible,
  including some that still live in the old `numerique-gouv`
  organization.
* Centralize the Renovate configuration alongside the workflows.

Inspired by the Accounts project, which recently simplified and
reorganized its CI setup.

This PR starts moving meet's CI to the shared repository so we can
validate the approach on a real project. For now, reusable
workflows are pinned to `main`; once we agree on the structure and
content of the central repository, they should be pinned to a
specific commit SHA instead.
2026-10-01 00:13:36 +02:00
35 changed files with 208 additions and 528 deletions
+9
View File
@@ -0,0 +1,9 @@
[codespell]
# Files that are not English, or generated
skip = ./.git,*.pdf,*.po,*.pot,*.json,*.lock,package-lock.json,
./LICENSES,
./src/summary/summary/core/locales,
./src/summary/summary/core/prompt.py
# Valid words in French (connexion) or in the code (statics)
ignore-words-list = connexion,statics
check-filenames = true
+20
View File
@@ -0,0 +1,20 @@
# Debian 13 base image (python:3.14-slim): no fixed version available yet.
# Review regularly and remove entries once Debian ships a fix.
# util-linux
CVE-2026-76642
CVE-2026-78408
CVE-2026-78409
CVE-2026-78410
# acl
CVE-2026-54369
# ncurses
CVE-2025-69720
# systemd
CVE-2026-16742
# perl-base (fix deferred by Debian)
CVE-2026-9538
+19
View File
@@ -0,0 +1,19 @@
name: Changelog Workflow
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
changelog:
uses: suitenumerique/ci/.github/workflows/_changelog.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
+22 -176
View File
@@ -11,180 +11,30 @@ permissions:
contents: read contents: read
jobs: jobs:
lint-git:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' # Makes sense only for pull requests
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 0
- name: show
run: git log
- name: Enforce absence of print statements in code
if: always()
run: |
! git diff origin/${{ github.event.pull_request.base.ref }}..HEAD -- . ':(exclude).github/workflows/**' | grep "print("
- name: Check absence of fixup commits
if: always()
run: |
! git log | grep 'fixup!'
- name: Install uv
if: always()
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Lint commit messages added to main
if: always()
run: uvx --no-build --from gitlint-core==0.19.1 gitlint --commits origin/${{ github.event.pull_request.base.ref }}..HEAD
check-changelog: lint-python:
runs-on: ubuntu-latest name: lint ${{ matrix.service }}
if: | strategy:
contains(github.event.pull_request.labels.*.name, 'noChangeLog') == false && fail-fast: false
github.event_name == 'pull_request' matrix:
permissions: include:
contents: read - service: backend
steps: working_directory: src/backend
- name: Checkout repository pylint_targets: meet demo core
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - service: agents
with: working_directory: src/agents
fetch-depth: 50 pylint_targets: ""
- name: Check that the CHANGELOG has been modified in the current branch - service: summary
run: git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.after }} | grep 'CHANGELOG.md' working_directory: src/summary
pylint_targets: ""
lint-changelog: uses: suitenumerique/ci/.github/workflows/_python-lint.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
runs-on: ubuntu-latest with:
permissions: working_directory: ${{ matrix.working_directory }}
contents: read python_version: "3.13"
steps: pylint_targets: ${{ matrix.pylint_targets }}
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Check CHANGELOG max line length
run: |
max_line_length=$(cat CHANGELOG.md | grep -Ev "^\[.*\]: https://github.com" | wc -L)
if [ $max_line_length -ge 80 ]; then
echo "ERROR: CHANGELOG has lines longer than 80 characters."
exit 1
fi
build-mails:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: src/mail
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version: "22"
- name: Restore the mail templates
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
id: mail-templates
with:
path: "src/backend/core/templates/mail"
key: mail-templates-${{ hashFiles('src/mail/mjml') }}
- name: Install yarn
if: steps.mail-templates.outputs.cache-hit != 'true'
run: npm install -g --ignore-scripts yarn@1.22.22
- name: Install node dependencies
if: steps.mail-templates.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile --ignore-scripts
- name: Build mails
if: steps.mail-templates.outputs.cache-hit != 'true'
run: yarn build
- name: Cache mail templates
if: steps.mail-templates.outputs.cache-hit != 'true'
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: "src/backend/core/templates/mail"
key: mail-templates-${{ hashFiles('src/mail/mjml') }}
lint-back:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: src/backend
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install the project
run: uv sync --locked --all-extras
- name: Check code formatting with ruff
run: uv run --no-sync --no-build ruff format . --diff
- name: Lint code with ruff
run: uv run --no-sync --no-build ruff check .
- name: Lint code with pylint
run: uv run --no-sync --no-build pylint meet demo core
lint-agents:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: src/agents
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install the project
run: uv sync --locked --all-extras --no-build
- name: Check code formatting with ruff
run: uv run --no-sync --no-build ruff format . --diff
- name: Lint code with ruff
run: uv run --no-sync --no-build ruff check .
lint-summary:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: src/summary
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Install Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install the project
run: uv sync --locked --all-extras
- name: Check code formatting with ruff
run: uv run --no-sync --no-build ruff format . --diff
- name: Lint code with ruff
run: uv run --no-sync --no-build ruff check .
test-back: test-back:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build-mails
permissions: permissions:
contents: read contents: read
defaults: defaults:
@@ -244,12 +94,8 @@ jobs:
sudo mkdir -p /data/media && \ sudo mkdir -p /data/media && \
sudo mkdir -p /data/static sudo mkdir -p /data/static
- name: Restore the mail templates - name: Build or restore the mail templates
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 uses: suitenumerique/ci/actions/mail-templates@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
id: mail-templates
with:
path: "src/backend/core/templates/mail"
key: mail-templates-${{ hashFiles('src/mail/mjml') }}
# Creates the access key and the bucket on startup # Creates the access key and the bucket on startup
- name: Start Garage - name: Start Garage
+14
View File
@@ -0,0 +1,14 @@
name: Project quality Workflow
on:
pull_request:
permissions:
contents: read
jobs:
quality:
uses: suitenumerique/ci/.github/workflows/_project-quality.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
with:
print_check_paths: src/backend src/summary src/agents
codespell_ignore_words: "unsecure"
-33
View File
@@ -1,33 +0,0 @@
name: Download Crowdin translations
on:
workflow_dispatch:
types: [file-fully-translated]
permissions:
contents: write
pull-requests: write
jobs:
crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: Download Crowdin files
uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2.17.0
with:
upload_sources: false
upload_translations: false
download_translations: true
localization_branch_name: l10n_crowdin_translations
create_pull_request: true
pull_request_title: "New Crowdin translations"
pull_request_body: "New Crowdin pull request with translations"
pull_request_base_branch_name: "main"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
CROWDIN_BASE_PATH: ${{ github.workspace }}
+49 -252
View File
@@ -1,5 +1,5 @@
name: Docker Hub Workflow name: Docker images
run-name: Docker Hub Workflow run-name: Docker images
on: on:
workflow_dispatch: workflow_dispatch:
@@ -15,265 +15,62 @@ on:
permissions: permissions:
contents: read contents: read
env:
DOCKER_USER: 1001:127
DOCKER_CONTAINER_REGISTRY_HOSTNAME: docker.io
DOCKER_CONTAINER_REGISTRY_NAMESPACE: lasuite
IS_MULTI_PLATFORM_BUILD: ${{ startsWith(github.ref, 'refs/tags/v') }}
BUILD_PLATFORMS: ${{ startsWith(github.ref, 'refs/tags/v') && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
jobs: jobs:
build-and-push-backend: build-and-push:
runs-on: ubuntu-latest name: ${{ matrix.service }}
permissions: strategy:
contents: read fail-fast: false
steps: matrix:
- include:
name: Checkout repository - service: backend
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 image_name: lasuite/meet-backend
- context: .
name: Set up QEMU file: ./Dockerfile
if: env.IS_MULTI_PLATFORM_BUILD == 'true' target: backend-production
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - service: frontend
- image_name: lasuite/meet-frontend
name: Set up Docker Buildx context: .
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 file: ./src/frontend/Dockerfile
- target: frontend-production
name: Docker meta - service: frontend-dinum
id: meta image_name: lasuite/meet-frontend-dinum
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 context: .
with: file: ./docker/dinum-frontend/Dockerfile
images: '${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-backend' target: frontend-production
- - service: summary
name: Login to DockerHub image_name: lasuite/meet-summary
if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') context: ./src/summary
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 file: ./src/summary/Dockerfile
with: target: production
username: ${{ secrets.DOCKER_HUB_USER }} - service: agents
password: ${{ secrets.DOCKER_HUB_PASSWORD }} image_name: lasuite/meet-agents
- context: ./src/agents
name: Run trivy scan file: ./src/agents/Dockerfile
uses: numerique-gouv/action-trivy-cache@d6e94cfb488f03a0b3e8b8739aad94e74d24d8da # main target: production
with: uses: suitenumerique/ci/.github/workflows/_docker-publish.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
docker-build-args: '--target backend-production -f Dockerfile' with:
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-backend:${{ github.sha }}' image_name: ${{ matrix.image_name }}
- context: ${{ matrix.context }}
name: Build and push file: ${{ matrix.file }}
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 target: ${{ matrix.target }}
with: docker_user: "1001:127"
context: . is_multi_platform: ${{ startsWith(github.ref, 'refs/tags/v') }}
target: backend-production should_push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }}
platforms: ${{ env.BUILD_PLATFORMS }} trivy_scan: true
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000 trivy_ignore_files: ./.github/.trivyignore
push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }} secrets:
tags: ${{ steps.meta.outputs.tags }} DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }}
labels: ${{ steps.meta.outputs.labels }} DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
build-and-push-frontend-generic:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
-
name: Set up QEMU
if: env.IS_MULTI_PLATFORM_BUILD == 'true'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
-
name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: '${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-frontend'
-
name: Login to DockerHub
if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@d6e94cfb488f03a0b3e8b8739aad94e74d24d8da # main
with:
docker-build-args: '-f src/frontend/Dockerfile --target frontend-production'
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-frontend:${{ github.sha }}'
-
name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: .
file: ./src/frontend/Dockerfile
target: frontend-production
platforms: ${{ env.BUILD_PLATFORMS }}
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-frontend-dinum:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
-
name: Set up QEMU
if: env.IS_MULTI_PLATFORM_BUILD == 'true'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
-
name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: '${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-frontend-dinum'
-
name: Login to DockerHub
if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@d6e94cfb488f03a0b3e8b8739aad94e74d24d8da # main
with:
docker-build-args: '-f docker/dinum-frontend/Dockerfile --target frontend-production'
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-frontend-dinum:${{ github.sha }}'
-
name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: .
file: ./docker/dinum-frontend/Dockerfile
target: frontend-production
platforms: ${{ env.BUILD_PLATFORMS }}
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-summary:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
-
name: Set up QEMU
if: env.IS_MULTI_PLATFORM_BUILD == 'true'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
-
name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: '${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-summary'
-
name: Login to DockerHub
if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@d6e94cfb488f03a0b3e8b8739aad94e74d24d8da # main
continue-on-error: true
with:
docker-build-args: '-f src/summary/Dockerfile --target production'
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-summary:${{ github.sha }}'
docker-context: './src/summary'
-
name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: ./src/summary
file: ./src/summary/Dockerfile
target: production
platforms: ${{ env.BUILD_PLATFORMS }}
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-and-push-agents:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
-
name: Set up QEMU
if: env.IS_MULTI_PLATFORM_BUILD == 'true'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
-
name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: lasuite/meet-agents
-
name: Login to DockerHub
if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/')
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@d6e94cfb488f03a0b3e8b8739aad94e74d24d8da # main
continue-on-error: true
with:
docker-build-args: '-f src/agents/Dockerfile --target production'
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-agents:${{ github.sha }}'
docker-context: './src/agents'
-
name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: ./src/agents
file: ./src/agents/Dockerfile
target: production
platforms: ${{ env.BUILD_PLATFORMS }}
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
push: ${{ github.event_name != 'pull_request' || startsWith(github.head_ref, 'integration/') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
notify-argocd: notify-argocd:
permissions: permissions:
contents: read contents: read
needs: needs:
- build-and-push-frontend-generic - build-and-push
- build-and-push-frontend-dinum
- build-and-push-backend
- build-and-push-summary
- build-and-push-agents
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
steps: steps:
- uses: numerique-gouv/action-argocd-webhook-notification@cac2ee67896eb13e84e804f60c4271370424eaa8 # main - uses: suitenumerique/ci/actions/argocd-webhook-notification@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
id: notify id: notify
with: with:
deployment_repo_path: "${{ secrets.DEPLOYMENT_REPO_URL }}" deployment_repo_path: "${{ secrets.DEPLOYMENT_REPO_URL }}"
+7 -23
View File
@@ -1,33 +1,17 @@
name: Release Chart name: Release Helm chart
run-name: Release Chart
on: on:
push: push:
branches:
- main
paths: paths:
- src/helm/meet/** - src/helm/meet/**
permissions:
contents: read
jobs: jobs:
release: release:
permissions: permissions:
contents: write contents: write
runs-on: ubuntu-latest uses: suitenumerique/ci/.github/workflows/_release-helm-chart.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 0
- name: Cleanup
run: rm -rf ./src/helm/extra
- name: Install Helm
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- name: Publish Helm charts
uses: numerique-gouv/helm-gh-pages@2cf477ae49d7c70037ceb1685803f4f7bad9b981 # add-overwrite-option
with:
charts_dir: ./src/helm
linting: on
token: ${{ secrets.GITHUB_TOKEN }}
+21
View File
@@ -0,0 +1,21 @@
name: Security analysis
on:
push:
branches:
- main
pull_request:
branches:
- "**"
permissions: {}
jobs:
zizmor:
permissions:
contents: read
actions: read
security-events: write
uses: suitenumerique/ci/.github/workflows/_zizmor.yml@ca6401ac83e981e5b0a94f06f68baaa6e6d0a436 # v0.0.1
with:
config: .github/zizmor.yml
+5
View File
@@ -0,0 +1,5 @@
rules:
unpinned-uses:
config:
policies:
"suitenumerique/*": ref-pin
+1 -1
View File
@@ -407,7 +407,7 @@ and this project adheres to
### Fixed ### Fixed
- ♿️(frontend) improve accessibilty of the Effects panel #1401 - ♿️(frontend) improve accessibility of the Effects panel #1401
## [1.20.0] - 2026-06-12 ## [1.20.0] - 2026-06-12
+2 -3
View File
@@ -37,14 +37,13 @@ RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev uv sync --locked --no-dev
# ---- mails ---- # ---- mails ----
FROM node:22 AS mail-builder FROM node:22-alpine AS mail-builder
COPY ./src/mail /mail/app COPY ./src/mail /mail/app
WORKDIR /mail/app WORKDIR /mail/app
RUN yarn install --frozen-lockfile && \ RUN npm ci --ignore-scripts && npm run build
yarn build
# ---- static link collector ---- # ---- static link collector ----
+8 -8
View File
@@ -55,12 +55,12 @@ function _docker_compose() {
function _dc_run() { function _dc_run() {
_set_user _set_user
user_args="--user=$USER_ID" user_args=()
if [ -z $USER_ID ]; then if [ -n "$USER_ID" ]; then
user_args="" user_args=("--user=$USER_ID")
fi fi
_docker_compose run --rm $user_args "$@" _docker_compose run --rm "${user_args[@]}" "$@"
} }
# _dc_exec: wrap docker compose exec command # _dc_exec: wrap docker compose exec command
@@ -74,12 +74,12 @@ function _dc_exec() {
echo "🐳(compose) exec command: '\$@'" echo "🐳(compose) exec command: '\$@'"
user_args="--user=$USER_ID" user_args=()
if [ -z $USER_ID ]; then if [ -n "$USER_ID" ]; then
user_args="" user_args=("--user=$USER_ID")
fi fi
_docker_compose exec $user_args "$@" _docker_compose exec "${user_args[@]}" "$@"
} }
# _django_manage: wrap django's manage.py command with docker compose # _django_manage: wrap django's manage.py command with docker compose
+1 -1
View File
@@ -40,7 +40,7 @@ if [ -n "$CUSTOM_LOGO_URL" ]; then
[[ "$IS_SVG" == false ]] && echo "[custom-logo] ERROR: not a valid SVG file" >&2 && exit 1 [[ "$IS_SVG" == false ]] && echo "[custom-logo] ERROR: not a valid SVG file" >&2 && exit 1
mv -f "$TMP_FILE" "$LOGO_FILE" mv -f "$TMP_FILE" "$LOGO_FILE"
echo "[custom-logo] INFO: Custom logo downloaded successfuly" echo "[custom-logo] INFO: Custom logo downloaded successfully"
fi fi
mv src/backend/* ./ mv src/backend/* ./
+1 -1
View File
@@ -7,7 +7,7 @@ gunicorn -b 0.0.0.0:8000 meet.wsgi:application --log-file - &
bin/run & bin/run &
# if the current shell is killed, also terminate all its children # if the current shell is killed, also terminate all its children
trap "pkill SIGTERM -P $$" SIGTERM trap 'pkill -TERM -P $$' SIGTERM
# wait for a single child to finish, # wait for a single child to finish,
wait -n wait -n
+4 -5
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -o errexit set -o errexit
CURRENT_DIR=$(pwd)
NAMESPACE=${1:-meet} NAMESPACE=${1:-meet}
SECRET_NAME=${2:-bitwarden-cli-meet} SECRET_NAME=${2:-bitwarden-cli-meet}
TEMP_SECRET_FILE=$(mktemp) TEMP_SECRET_FILE=$(mktemp)
@@ -30,10 +29,10 @@ check_secret_exists() {
# Collect user input securely # Collect user input securely
get_user_input() { get_user_input() {
echo "Please provide the following information:" echo "Please provide the following information:"
read -p "Enter your Vaultwarden email login: " LOGIN read -r -p "Enter your Vaultwarden email login: " LOGIN
read -s -p "Enter your Vaultwarden password: " PASSWORD read -r -s -p "Enter your Vaultwarden password: " PASSWORD
echo echo
read -p "Enter your Vaultwarden server url: " URL read -r -p "Enter your Vaultwarden server url: " URL
} }
# Create and apply the secret # Create and apply the secret
@@ -77,7 +76,7 @@ main() {
exit 0 exit 0
fi fi
echo -e ${TEMP_SECRET_FILE} echo -e "${TEMP_SECRET_FILE}"
get_user_input get_user_input
echo -e "\nCreating Vaultwarden secret…" echo -e "\nCreating Vaultwarden secret…"
+2 -2
View File
@@ -3,7 +3,7 @@
mkdir -p "$(dirname -- "${BASH_SOURCE[0]}")/../.git/hooks/" mkdir -p "$(dirname -- "${BASH_SOURCE[0]}")/../.git/hooks/"
PRE_COMMIT_FILE="$(dirname -- "${BASH_SOURCE[0]}")/../.git/hooks/pre-commit" PRE_COMMIT_FILE="$(dirname -- "${BASH_SOURCE[0]}")/../.git/hooks/pre-commit"
cat <<'EOF' >$PRE_COMMIT_FILE cat <<'EOF' >"$PRE_COMMIT_FILE"
#!/bin/bash #!/bin/bash
# directories containing potential secrets # directories containing potential secrets
@@ -27,4 +27,4 @@ for d in $DIRS; do
done done
EOF EOF
chmod +x $PRE_COMMIT_FILE chmod +x "$PRE_COMMIT_FILE"
+1 -1
View File
@@ -68,7 +68,7 @@ fi
# Ask user for release version number # Ask user for release version number
echo "" echo ""
read -p "Enter release version number (e.g., 1.2.3): " VERSION read -r -p "Enter release version number (e.g., 1.2.3): " VERSION
# Validate version format (basic semver check) # Validate version format (basic semver check)
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
git submodule update --init --recursive git submodule update --init --recursive
# shellcheck disable=SC2016
git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx' git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'
+1 -1
View File
@@ -8,6 +8,6 @@ environments=$(awk '/environments:/ {flag=1; next} flag && NF {print} !NF {flag=
for env in $environments; do for env in $environments; do
echo "################### $env lint ###################" echo "################### $env lint ###################"
helmfile -e $env -f src/helm/helmfile.yaml lint || exit 1 helmfile -e "$env" -f src/helm/helmfile.yaml lint || exit 1
echo -e "\n" echo -e "\n"
done done
+2 -2
View File
@@ -172,7 +172,7 @@ services:
working_dir: /app working_dir: /app
node: node:
image: node:22 image: node:22-alpine
user: "${DOCKER_USER:-1000}" user: "${DOCKER_USER:-1000}"
environment: environment:
HOME: /tmp HOME: /tmp
@@ -271,7 +271,7 @@ services:
- /app/.venv - /app/.venv
redis-summary: redis-summary:
image: redis image: redis:5
ports: ports:
- "6379:6379" - "6379:6379"
+1 -1
View File
@@ -1,7 +1,7 @@
# Bureautix proxy overrides # Bureautix proxy overrides
# #
# Builds submitted through the Docker API of the Podman service get none of # Builds submitted through the Docker API of the Podman service get none of
# the proxy variables in their RUN steps. We need to pass the http_proxy explicitely # the proxy variables in their RUN steps. We need to pass the http_proxy explicitly
# otherwise all connections fail during the build. # otherwise all connections fail during the build.
x-proxy-vars: &proxy-vars x-proxy-vars: &proxy-vars
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"extends": ["github>numerique-gouv/renovate-configuration"], "extends": ["github>suitenumerique/ci//renovate/default"],
"dependencyDashboard": true, "dependencyDashboard": true,
"labels": ["dependencies", "noChangeLog"], "labels": ["dependencies", "noChangeLog"],
"packageRules": [ "packageRules": [
+1 -1
View File
@@ -21,7 +21,7 @@ const { initI18n, translateUI } = require("../common/i18n");
document.querySelector("#close-msg").style.display = "block"; document.querySelector("#close-msg").style.display = "block";
}) })
.catch((e) => { .catch((e) => {
console.error(`Error occured: ${e}`); console.error(`Error occurred: ${e}`);
}) })
.finally(() => { .finally(() => {
// NOTE: doesn't work with the desktop client — the browser considers // NOTE: doesn't work with the desktop client — the browser considers
@@ -24,7 +24,7 @@ class BaseEgressService:
def _get_filepath(self, filename: str, extension: str) -> str: def _get_filepath(self, filename: str, extension: str) -> str:
"""Construct the file path for a given filename and extension. """Construct the file path for a given filename and extension.
Unsecure method, doesn't handle paths robustly and securely. Insecure method, doesn't handle paths robustly and securely.
""" """
return f"{self._config.output_folder}/{filename}.{extension}" return f"{self._config.output_folder}/{filename}.{extension}"
@@ -27,7 +27,7 @@ def test_api_files_list_anonymous_not_allowed():
def test_api_files_list_authentificated_user_allowed(): def test_api_files_list_authentificated_user_allowed():
""" """
Authentificated users should be allowed to list files Authenticated users should be allowed to list files
""" """
user = factories.UserFactory() user = factories.UserFactory()
client = APIClient() client = APIClient()
@@ -458,7 +458,7 @@ def test_mute_participant_livekit_token_presence_check_twirp_error_forbidden(
room = RoomFactory() room = RoomFactory()
mock_livekit_client.room.get_participant.side_effect = TwirpError( mock_livekit_client.room.get_participant.side_effect = TwirpError(
msg="an error occured", code="not_found", status=500 msg="an error occurred", code="not_found", status=500
) )
user = AnonymousUser() user = AnonymousUser()
@@ -1,5 +1,5 @@
""" """
Test SIP mamagement service. Test SIP management service.
""" """
# pylint: disable=W0212 # pylint: disable=W0212
+1 -1
View File
@@ -121,7 +121,7 @@ const config: Config = {
}, },
tokens: defineTokens({ tokens: defineTokens({
/* we take a few things from the panda preset but for now we clear out some stuff. /* we take a few things from the panda preset but for now we clear out some stuff.
* This way we'll only add the things we need step by step and prevent using lots of differents things. * This way we'll only add the things we need step by step and prevent using lots of different things.
*/ */
...pandaPreset.theme.tokens, ...pandaPreset.theme.tokens,
colors: defineTokens.colors({ colors: defineTokens.colors({
@@ -158,7 +158,7 @@ export const Conference = ({
* *
* Issue: On Firefox behind proxy configurations, WebSocket signaling fails to establish. * Issue: On Firefox behind proxy configurations, WebSocket signaling fails to establish.
* Symptom: Client receives HTTP 200 instead of expected 101 (Switching Protocols). * Symptom: Client receives HTTP 200 instead of expected 101 (Switching Protocols).
* Root Cause: Certificate/security issue where the initial request is considered unsecure. * Root Cause: Certificate/security issue where the initial request is considered insecure.
* *
* Solution: Pre-establish a WebSocket connection to the signaling server, which fails. * Solution: Pre-establish a WebSocket connection to the signaling server, which fails.
* This "primes" the connection, allowing subsequent WebSocket establishments to work correctly. * This "primes" the connection, allowing subsequent WebSocket establishments to work correctly.
+3 -4
View File
@@ -1,10 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
docker image ls | grep readme-generator-for-helm if ! docker image ls | grep readme-generator-for-helm; then
if [ "$?" -ne "0" ]; then
git clone https://github.com/bitnami/readme-generator-for-helm.git /tmp/readme-generator-for-helm git clone https://github.com/bitnami/readme-generator-for-helm.git /tmp/readme-generator-for-helm
cd /tmp/readme-generator-for-helm cd /tmp/readme-generator-for-helm || exit 1
docker build -t readme-generator-for-helm:latest . docker build -t readme-generator-for-helm:latest .
cd $(dirname -- "${BASH_SOURCE[0]}") cd "$(dirname -- "${BASH_SOURCE[0]}")" || exit 1
fi fi
docker run --rm -it -v .:/source -w /source readme-generator-for-helm:latest readme-generator -v values.yaml -r README.md docker run --rm -it -v .:/source -w /source readme-generator-for-helm:latest readme-generator -v values.yaml -r README.md
+1 -1
View File
@@ -51,7 +51,7 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }} {{- end }}
{{/* {{/*
transform dictionnary of environment variables transform dictionary of environment variables
Usage : {{ include "meet.env.transformDict" .Values.envVars }} Usage : {{ include "meet.env.transformDict" .Values.envVars }}
Example: Example:
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/bin/sh
set -eo pipefail set -e
# Run html-to-text to convert all html files to text files # Run html-to-text to convert all html files to text files
DIR_MAILS="../backend/core/templates/mail/" DIR_MAILS="../backend/core/templates/mail/"
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/sh
# Run mjml command to convert all mjml templates to html files # Run mjml command to convert all mjml templates to html files
DIR_MAILS="../backend/core/templates/mail/html/" DIR_MAILS="../backend/core/templates/mail/html/"
+2 -2
View File
@@ -9,8 +9,8 @@
}, },
"private": true, "private": true,
"scripts": { "scripts": {
"build-mjml-to-html": "bash ./bin/mjml-to-html", "build-mjml-to-html": "sh ./bin/mjml-to-html",
"build-html-to-plain-text": "bash ./bin/html-to-plain-text", "build-html-to-plain-text": "sh ./bin/html-to-plain-text",
"build": "npm run build-mjml-to-html && npm run build-html-to-plain-text" "build": "npm run build-mjml-to-html && npm run build-html-to-plain-text"
}, },
"volta": { "volta": {