Compare commits

..

7 Commits

Author SHA1 Message Date
lebaudantoine f7a8fcfce9 👷(ci) re-enable Trivy scan in CI for image builds
Restore Trivy scanning jobs for built images after the situation
was clarified, ensuring vulnerability checks are active again.
2026-03-18 10:09:20 +01:00
renovate[bot] 7c05aedcfe ⬆️(dependencies) update PyJWT to v2.12.0 [SECURITY] 2026-03-17 18:33:39 +01:00
lebaudantoine 7347fc7c86 🚨(doc) fix changelog linting
Merge an outside contribution, didn't notice it broke the changelog fix it.
2026-03-17 16:45:04 +01:00
Hadrien Blanc ada7d9a666 🐛(frontend) fix dimension mismatch in BackgroundCustomProcessor
The getImageData call was using PROCESSING_WIDTH for both dimensions
instead of PROCESSING_WIDTH and PROCESSING_HEIGHT. This caused the
source image data to be 256x256 instead of the expected 256x144, leading
to buffer overflow when writing to the segmentation mask and potential
visual artifacts in Firefox background effects.
2026-03-17 16:41:40 +01:00
lebaudantoine 0cb3fb8e3c 🔧(ci) explicitly set Docker Hub CI permissions to read-only
Define read-only permissions in the workflow to clarify the
expected access level and follow the principle of least
privilege.
2026-03-15 16:53:07 +01:00
lebaudantoine dcb788b57b 🔒️(backend) avoid information exposure through exception messages
Sanitize error handling to prevent leaking internal details when
invalid or malicious requests are sent to the API.

Return generic error responses to reduce the risk of information
disclosure during probing attempts.
2026-03-13 17:33:55 +01:00
lebaudantoine 73bcb9d598 🐛(backend) fix unescaped dot in regex pattern
The dot before (?P<extension>...) was not escaped and matched any
character instead of a literal period.

Escape it to align with MEDIA_STORAGE_URL_PATTERN, which correctly
uses \. for the file extension separator.
2026-03-13 16:19:36 +01:00
9 changed files with 65 additions and 50 deletions
+48 -33
View File
@@ -12,6 +12,9 @@ on:
branches:
- 'main'
permissions:
contents: read
env:
DOCKER_USER: 1001:127
DOCKER_CONTAINER_REGISTRY_HOSTNAME: docker.io
@@ -20,6 +23,8 @@ env:
jobs:
build-and-push-backend:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
@@ -43,12 +48,12 @@ jobs:
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
# -
# name: Run trivy scan
# uses: numerique-gouv/action-trivy-cache@main
# with:
# docker-build-args: '--target backend-production -f Dockerfile'
# docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-backend:${{ github.sha }}'
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@main
with:
docker-build-args: '--target backend-production -f Dockerfile'
docker-image-name: '${{ env.DOCKER_CONTAINER_REGISTRY_HOSTNAME }}/${{ env.DOCKER_CONTAINER_REGISTRY_NAMESPACE }}/meet-backend:${{ github.sha }}'
-
name: Build and push
uses: docker/build-push-action@v6
@@ -63,6 +68,8 @@ jobs:
build-and-push-frontend-generic:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
@@ -86,12 +93,12 @@ jobs:
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
# -
# name: Run trivy scan
# uses: numerique-gouv/action-trivy-cache@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: Run trivy scan
uses: numerique-gouv/action-trivy-cache@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@v6
@@ -107,6 +114,8 @@ jobs:
build-and-push-frontend-dinum:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
@@ -130,12 +139,12 @@ jobs:
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
# -
# name: Run trivy scan
# uses: numerique-gouv/action-trivy-cache@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: Run trivy scan
uses: numerique-gouv/action-trivy-cache@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@v6
@@ -151,6 +160,8 @@ jobs:
build-and-push-summary:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
@@ -174,13 +185,13 @@ jobs:
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
# -
# name: Run trivy scan
# uses: numerique-gouv/action-trivy-cache@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 }}'
-
name: Run trivy scan
uses: numerique-gouv/action-trivy-cache@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
@@ -197,6 +208,8 @@ jobs:
build-and-push-agents:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
-
name: Checkout repository
@@ -220,14 +233,14 @@ jobs:
with:
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
# -
# name: Run trivy scan
# uses: numerique-gouv/action-trivy-cache@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: Run trivy scan
uses: numerique-gouv/action-trivy-cache@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@v6
@@ -242,6 +255,8 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
notify-argocd:
permissions:
contents: read
needs:
- build-and-push-frontend-generic
- build-and-push-frontend-dinum
+4
View File
@@ -28,6 +28,8 @@ and this project adheres to
- ♻️(backend) align Application model field with `is_active` convention #1133
- 🔐(backend) avoids revealing the inactive status of an application #1135
- ⚡️(helm) reduce initialDelaySeconds and add periods seconds #1139
- 🔒️(backend) avoid information exposure through exception messages #1144
- ⬆️(dependencies) update PyJWT to v2.12.0 [SECURITY] #1151
### Fixed
@@ -35,6 +37,8 @@ and this project adheres to
- 🩹(backend) add page_size to pagination for room endpoints #1131
- 🐛(backend) refactor lobby throttling to use participant id #1129
- 🩹(backend) ignore non-recording uploads in storage webhook handler #1142
- 🐛(frontend) fix dimension mismatch in BackgroundCustomProcessor #1116
## [1.10.0] - 2026-03-05
+3 -5
View File
@@ -488,9 +488,7 @@ class RoomViewSet(
if status_code == drf_status.HTTP_500_INTERNAL_SERVER_ERROR:
raise e
return drf_response.Response(
{"status": "error", "message": str(e)}, status=status_code
)
return drf_response.Response({"status": "error"}, status=status_code)
@decorators.action(
detail=False,
@@ -757,10 +755,10 @@ class RecordingViewSet(
recording_id = parser.get_recording_id(request.data)
except ParsingEventDataError as e:
raise drf_exceptions.PermissionDenied(f"Invalid request data: {e}") from e
raise drf_exceptions.PermissionDenied("Invalid request data.") from e
except InvalidBucketError as e:
raise drf_exceptions.PermissionDenied("Invalid bucket specified") from e
raise drf_exceptions.PermissionDenied("Invalid bucket specified.") from e
except InvalidFilepathError:
return drf_response.Response(
+1 -1
View File
@@ -14,7 +14,7 @@ FILE_EXT_REGEX = r"[a-zA-Z0-9]{1,10}"
# pylint: disable=line-too-long
RECORDING_STORAGE_URL_PATTERN = re.compile(
f"{settings.MEDIA_URL:s}{settings.RECORDING_OUTPUT_FOLDER}/(?P<recording_id>{UUID_REGEX:s})\.(?P<extension>{FILE_EXT_REGEX:s})"
rf"{settings.MEDIA_URL:s}{settings.RECORDING_OUTPUT_FOLDER}/(?P<recording_id>{UUID_REGEX:s})\.(?P<extension>{FILE_EXT_REGEX:s})"
)
MEDIA_STORAGE_URL_PATTERN = re.compile(
@@ -95,7 +95,7 @@ def test_save_recording_parsing_error(recording_settings, mock_get_parser, clien
)
assert response.status_code == 403
assert response.json() == {"detail": "Invalid request data: Error message"}
assert response.json() == {"detail": "Invalid request data."}
def test_save_recording_bucket_error(recording_settings, mock_get_parser, client):
@@ -112,7 +112,7 @@ def test_save_recording_bucket_error(recording_settings, mock_get_parser, client
)
assert response.status_code == 403
assert response.json() == {"detail": "Invalid bucket specified"}
assert response.json() == {"detail": "Invalid bucket specified."}
def test_save_recording_filetype_error(recording_settings, mock_get_parser):
@@ -77,7 +77,6 @@ def test_missing_auth_header(client, serialized_event_data, mock_livekit_config)
assert response.status_code == 401
assert response.json() == {
"status": "error",
"message": "Authorization header missing",
}
@@ -91,7 +90,7 @@ def test_invalid_payload(client, auth_token, mock_livekit_config):
)
assert response.status_code == 400
assert response.json() == {"status": "error", "message": "Invalid webhook payload"}
assert response.json() == {"status": "error"}
def test_unknown_event_type(client, mock_livekit_config):
@@ -116,7 +115,6 @@ def test_unknown_event_type(client, mock_livekit_config):
assert response.status_code == 422
assert response.json() == {
"status": "error",
"message": "Unknown webhook type: unknown_event_type",
}
+1 -1
View File
@@ -52,7 +52,7 @@ dependencies = [
"nested-multipart-parser==1.6.0",
"psycopg[binary]==3.3.2",
"pydantic==2.12.4",
"PyJWT==2.11.0",
"PyJWT==2.12.0",
"python-frontmatter==1.1.0",
"python-magic==0.4.27",
"requests==2.32.5",
+4 -4
View File
@@ -1251,7 +1251,7 @@ requires-dist = [
{ name = "nested-multipart-parser", specifier = "==1.6.0" },
{ name = "psycopg", extras = ["binary"], specifier = "==3.3.2" },
{ name = "pydantic", specifier = "==2.12.4" },
{ name = "pyjwt", specifier = "==2.11.0" },
{ name = "pyjwt", specifier = "==2.12.0" },
{ name = "python-frontmatter", specifier = "==1.1.0" },
{ name = "python-magic", specifier = "==0.4.27" },
{ name = "redis", specifier = "==5.2.1" },
@@ -1754,11 +1754,11 @@ wheels = [
[[package]]
name = "pyjwt"
version = "2.11.0"
version = "2.12.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
sdist = { url = "https://files.pythonhosted.org/packages/a8/10/e8192be5f38f3e8e7e046716de4cae33d56fd5ae08927a823bb916be36c1/pyjwt-2.12.0.tar.gz", hash = "sha256:2f62390b667cd8257de560b850bb5a883102a388829274147f1d724453f8fb02", size = 102511, upload-time = "2026-03-12T17:15:30.831Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
{ url = "https://files.pythonhosted.org/packages/15/70/70f895f404d363d291dcf62c12c85fdd47619ad9674ac0f53364d035925a/pyjwt-2.12.0-py3-none-any.whl", hash = "sha256:9bb459d1bdd0387967d287f5656bf7ec2b9a26645d1961628cda1764e087fd6e", size = 29700, upload-time = "2026-03-12T17:15:29.257Z" },
]
[[package]]
@@ -187,7 +187,7 @@ export class BackgroundCustomProcessor implements BackgroundProcessorInterface {
0,
0,
PROCESSING_WIDTH,
PROCESSING_WIDTH
PROCESSING_HEIGHT
)
}