mirror of
https://github.com/suitenumerique/meet.git
synced 2026-10-02 15:38:22 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7b05a4487 | |||
| 971a7295ca | |||
| bd0329d162 | |||
| cedaa32ab7 | |||
| 22adccb353 | |||
| 3ab651d6c7 | |||
| 919af928aa | |||
| 3ed38f1c48 | |||
| f172c5795e | |||
| 262b168414 | |||
| 6c371c8cb3 | |||
| 1a8906c0a1 | |||
| 99ba8e330e | |||
| 059e5f1ec4 | |||
| 39ab9359e4 | |||
| d0a0d60ece |
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -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 }}
|
|
||||||
@@ -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 }}"
|
||||||
|
|||||||
@@ -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 }}
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
rules:
|
||||||
|
unpinned-uses:
|
||||||
|
config:
|
||||||
|
policies:
|
||||||
|
"suitenumerique/*": ref-pin
|
||||||
+15
-1
@@ -10,6 +10,20 @@ and this project adheres to
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- 🔒(backend) throttle meeting link generation
|
||||||
|
- 🔒️(backend) add a daily cap on room creation
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 🐛(frontend) enforce recording-mode permissions on the checkboxes
|
||||||
|
- 🔒️(agents) fix util-linux CVEs reported by Cyberwatch
|
||||||
|
- 🔒️(backend) fix HIGH CVEs in Django and urllib3
|
||||||
|
- 🔒️(agents) upgrade libpcre2-8-0 to fix CVE-2026-103111
|
||||||
|
|
||||||
|
## [1.33.0] - 2026-09-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
- ✨(backend) purge rooms inactive for a configurable period
|
- ✨(backend) purge rooms inactive for a configurable period
|
||||||
- 🔨(makefile) add targets to list and download files stored in Garage
|
- 🔨(makefile) add targets to list and download files stored in Garage
|
||||||
|
|
||||||
@@ -393,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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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/* ./
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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…"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,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'
|
||||||
|
|||||||
@@ -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
@@ -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,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
|
||||||
|
|||||||
+119
-117
@@ -14,7 +14,7 @@ This document is a step-by-step guide that describes how to install LaSuite Meet
|
|||||||
|
|
||||||
If you do not have a kubernetes test cluster, you can install everything on a local kind cluster. In this case, the simplest way is to use our script located in this repo under **bin/start-kind.sh**.
|
If you do not have a kubernetes test cluster, you can install everything on a local kind cluster. In this case, the simplest way is to use our script located in this repo under **bin/start-kind.sh**.
|
||||||
|
|
||||||
IMPORTANT: The kind method will only deploy meet as a local instance(127.0.0.1) that can only be accessed from the device where it has been deployed.
|
IMPORTANT: The kind method will only deploy meet as a local instance(127.0.0.1) that can only be accessed from the device where it has been deployed.
|
||||||
|
|
||||||
To be able to use the script, you will need to install the following components:
|
To be able to use the script, you will need to install the following components:
|
||||||
|
|
||||||
@@ -311,120 +311,122 @@ frontend:
|
|||||||
|
|
||||||
These are the environmental options available on meet backend.
|
These are the environmental options available on meet backend.
|
||||||
|
|
||||||
| Option | Description | default |
|
| Option | Description | default |
|
||||||
|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| DATA_DIR | Data directory location | /data |
|
| DATA_DIR | Data directory location | /data |
|
||||||
| DJANGO_ALLOWED_HOSTS | Hosts that are allowed | [] |
|
| DJANGO_ALLOWED_HOSTS | Hosts that are allowed | [] |
|
||||||
| DJANGO_SECRET_KEY | Secret key used for Django security | |
|
| DJANGO_SECRET_KEY | Secret key used for Django security | |
|
||||||
| DJANGO_SILENCED_SYSTEM_CHECKS | Silence Django system checks | [] |
|
| DJANGO_SILENCED_SYSTEM_CHECKS | Silence Django system checks | [] |
|
||||||
| DJANGO_ALLOW_UNSECURE_USER_LISTING | Allow unsecure user listing | false |
|
| DJANGO_ALLOW_UNSECURE_USER_LISTING | Allow unsecure user listing | false |
|
||||||
| DB_ENGINE | Database engine used | django.db.backends.postgresql_psycopg2 |
|
| DB_ENGINE | Database engine used | django.db.backends.postgresql_psycopg2 |
|
||||||
| DB_NAME | Name of the database | meet |
|
| DB_NAME | Name of the database | meet |
|
||||||
| DB_USER | User used to connect to database | dinum |
|
| DB_USER | User used to connect to database | dinum |
|
||||||
| DB_PASSWORD | Password used to connect to the database | pass |
|
| DB_PASSWORD | Password used to connect to the database | pass |
|
||||||
| DB_HOST | Hostname of the database | localhost |
|
| DB_HOST | Hostname of the database | localhost |
|
||||||
| DB_PORT | Port to connect to database | 5432 |
|
| DB_PORT | Port to connect to database | 5432 |
|
||||||
| STORAGES_STATICFILES_BACKEND | Static file serving engine | whitenoise.storage.CompressedManifestStaticFilesStorage |
|
| STORAGES_STATICFILES_BACKEND | Static file serving engine | whitenoise.storage.CompressedManifestStaticFilesStorage |
|
||||||
| AWS_S3_ENDPOINT_URL | S3 host endpoint | |
|
| AWS_S3_ENDPOINT_URL | S3 host endpoint | |
|
||||||
| AWS_S3_ACCESS_KEY_ID | S3 access key | |
|
| AWS_S3_ACCESS_KEY_ID | S3 access key | |
|
||||||
| AWS_S3_SECRET_ACCESS_KEY | S3 secret key | |
|
| AWS_S3_SECRET_ACCESS_KEY | S3 secret key | |
|
||||||
| AWS_S3_REGION_NAME | S3 region | |
|
| AWS_S3_REGION_NAME | S3 region | |
|
||||||
| AWS_STORAGE_BUCKET_NAME | S3 bucket name | meet-media-storage |
|
| AWS_STORAGE_BUCKET_NAME | S3 bucket name | meet-media-storage |
|
||||||
| DJANGO_LANGUAGE_CODE | Default language | en-us |
|
| DJANGO_LANGUAGE_CODE | Default language | en-us |
|
||||||
| REDIS_URL | Redis endpoint | redis://redis:6379/1 |
|
| REDIS_URL | Redis endpoint | redis://redis:6379/1 |
|
||||||
| SESSION_COOKIE_AGE | Session cookie expiration in seconds | 43200 (12 hours) |
|
| SESSION_COOKIE_AGE | Session cookie expiration in seconds | 43200 (12 hours) |
|
||||||
| REQUEST_ENTRY_THROTTLE_RATES | Entry request throttle rates | 150/minute |
|
| ROOM_CREATION_THROTTLE_RATES | Room creation throttle rate per authenticated user | 50/minute | 50/minute |
|
||||||
| CREATION_CALLBACK_THROTTLE_RATES | Creation callback throttle rates | 600/minute |
|
| ROOM_CREATION_DAILY_THROTTLE_RATES | Daily room creation cap per authenticated user | 1000/day |
|
||||||
| SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK | Enable Django deploy check | false |
|
| REQUEST_ENTRY_THROTTLE_RATES | Entry request throttle rates | 150/minute |
|
||||||
| CSRF_TRUSTED_ORIGINS | CSRF trusted origins list | [] |
|
| CREATION_CALLBACK_THROTTLE_RATES | Creation callback throttle rates | 600/minute |
|
||||||
| FRONTEND_CUSTOM_CSS_URL | URL of an additional CSS file to load in the frontend app. If set, a `<link>` tag with this URL as href is added to the `<head>` of the frontend app | |
|
| SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK | Enable Django deploy check | false |
|
||||||
| FRONTEND_ANALYTICS | Analytics information | {} |
|
| CSRF_TRUSTED_ORIGINS | CSRF trusted origins list | [] |
|
||||||
| FRONTEND_SUPPORT | Crisp frontend support configuration, also you can pass help articles, with `help_article_transcript`, `help_article_recording`, `help_article_more_tools` | {} |
|
| FRONTEND_CUSTOM_CSS_URL | URL of an additional CSS file to load in the frontend app. If set, a `<link>` tag with this URL as href is added to the `<head>` of the frontend app | |
|
||||||
| FRONTEND_MANIFEST_LINK | Link to the "Learn more" button on the homepage | {} |
|
| FRONTEND_ANALYTICS | Analytics information | {} |
|
||||||
| FRONTEND_SILENCE_LIVEKIT_DEBUG | Silence LiveKit debug logs | false |
|
| FRONTEND_SUPPORT | Crisp frontend support configuration, also you can pass help articles, with `help_article_transcript`, `help_article_recording`, `help_article_more_tools` | {} |
|
||||||
| FRONTEND_IS_SILENT_LOGIN_ENABLED | Enable silent login feature | true |
|
| FRONTEND_MANIFEST_LINK | Link to the "Learn more" button on the homepage | {} |
|
||||||
| FRONTEND_FEEDBACK | Frontend feedback configuration | {} |
|
| FRONTEND_SILENCE_LIVEKIT_DEBUG | Silence LiveKit debug logs | false |
|
||||||
| FRONTEND_DOCUMENTATION_URL | URL of the documentation opened from the room options menu. If unset, the documentation menu item is hidden | |
|
| FRONTEND_IS_SILENT_LOGIN_ENABLED | Enable silent login feature | true |
|
||||||
| FRONTEND_USE_FRENCH_GOV_FOOTER | Show the French government footer in the homepage | false |
|
| FRONTEND_FEEDBACK | Frontend feedback configuration | {} |
|
||||||
| FRONTEND_USE_PROCONNECT_BUTTON | Show a "Login with ProConnect" button in the homepage instead of a "Login" button | false |
|
| FRONTEND_DOCUMENTATION_URL | URL of the documentation opened from the room options menu. If unset, the documentation menu item is hidden | |
|
||||||
| DJANGO_EMAIL_BACKEND | Email backend library | django.core.mail.backends.smtp.EmailBackend |
|
| FRONTEND_USE_FRENCH_GOV_FOOTER | Show the French government footer in the homepage | false |
|
||||||
| DJANGO_EMAIL_HOST | Host of the email server | |
|
| FRONTEND_USE_PROCONNECT_BUTTON | Show a "Login with ProConnect" button in the homepage instead of a "Login" button | false |
|
||||||
| DJANGO_EMAIL_HOST_USER | User to connect to the email server | |
|
| DJANGO_EMAIL_BACKEND | Email backend library | django.core.mail.backends.smtp.EmailBackend |
|
||||||
| DJANGO_EMAIL_HOST_PASSWORD | Password to connect to the email server | |
|
| DJANGO_EMAIL_HOST | Host of the email server | |
|
||||||
| DJANGO_EMAIL_PORT | Port to connect to the email server | |
|
| DJANGO_EMAIL_HOST_USER | User to connect to the email server | |
|
||||||
| DJANGO_EMAIL_USE_TLS | Enable TLS on email connection | false |
|
| DJANGO_EMAIL_HOST_PASSWORD | Password to connect to the email server | |
|
||||||
| DJANGO_EMAIL_USE_SSL | Enable SSL on email connection | false |
|
| DJANGO_EMAIL_PORT | Port to connect to the email server | |
|
||||||
| DJANGO_EMAIL_FROM | Email from account | from@example.com |
|
| DJANGO_EMAIL_USE_TLS | Enable TLS on email connection | false |
|
||||||
| EMAIL_BRAND_NAME | Email branding name | |
|
| DJANGO_EMAIL_USE_SSL | Enable SSL on email connection | false |
|
||||||
| EMAIL_SUPPORT_EMAIL | Support email address | |
|
| DJANGO_EMAIL_FROM | Email from account | from@example.com |
|
||||||
| EMAIL_LOGO_IMG | Email logo image | |
|
| EMAIL_BRAND_NAME | Email branding name | |
|
||||||
| EMAIL_DOMAIN | Email domain | |
|
| EMAIL_SUPPORT_EMAIL | Support email address | |
|
||||||
| EMAIL_APP_BASE_URL | Email app base URL | |
|
| EMAIL_LOGO_IMG | Email logo image | |
|
||||||
| DJANGO_CORS_ALLOW_ALL_ORIGINS | Allow all CORS origins | false |
|
| EMAIL_DOMAIN | Email domain | |
|
||||||
| DJANGO_CORS_ALLOWED_ORIGINS | Origins to allow (string list) | [] |
|
| EMAIL_APP_BASE_URL | Email app base URL | |
|
||||||
| DJANGO_CORS_ALLOWED_ORIGIN_REGEXES | Origins to allow (regex patterns) | [] |
|
| DJANGO_CORS_ALLOW_ALL_ORIGINS | Allow all CORS origins | false |
|
||||||
| SENTRY_DSN | Sentry server DSN | |
|
| DJANGO_CORS_ALLOWED_ORIGINS | Origins to allow (string list) | [] |
|
||||||
| DJANGO_CELERY_BROKER_URL | Celery broker host | redis://redis:6379/0 |
|
| DJANGO_CORS_ALLOWED_ORIGIN_REGEXES | Origins to allow (regex patterns) | [] |
|
||||||
| DJANGO_CELERY_BROKER_TRANSPORT_OPTIONS | Celery broker options | {} |
|
| SENTRY_DSN | Sentry server DSN | |
|
||||||
| OIDC_CREATE_USER | Create OIDC user if not exists | true |
|
| DJANGO_CELERY_BROKER_URL | Celery broker host | redis://redis:6379/0 |
|
||||||
| OIDC_VERIFY_SSL | Verify SSL for OIDC | true |
|
| DJANGO_CELERY_BROKER_TRANSPORT_OPTIONS | Celery broker options | {} |
|
||||||
| OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION | Fallback to email for identification | false |
|
| OIDC_CREATE_USER | Create OIDC user if not exists | true |
|
||||||
| OIDC_RP_SIGN_ALGO | Token verification algorithm used by OIDC | RS256 |
|
| OIDC_VERIFY_SSL | Verify SSL for OIDC | true |
|
||||||
| OIDC_RP_CLIENT_ID | OIDC client ID | meet |
|
| OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION | Fallback to email for identification | false |
|
||||||
| OIDC_RP_CLIENT_SECRET | OIDC client secret | |
|
| OIDC_RP_SIGN_ALGO | Token verification algorithm used by OIDC | RS256 |
|
||||||
| OIDC_OP_JWKS_ENDPOINT | OIDC endpoint for JWKS | |
|
| OIDC_RP_CLIENT_ID | OIDC client ID | meet |
|
||||||
| OIDC_OP_AUTHORIZATION_ENDPOINT | OIDC endpoint for authorization | |
|
| OIDC_RP_CLIENT_SECRET | OIDC client secret | |
|
||||||
| OIDC_OP_TOKEN_ENDPOINT | OIDC endpoint for token | |
|
| OIDC_OP_JWKS_ENDPOINT | OIDC endpoint for JWKS | |
|
||||||
| OIDC_OP_USER_ENDPOINT | OIDC endpoint for user | |
|
| OIDC_OP_AUTHORIZATION_ENDPOINT | OIDC endpoint for authorization | |
|
||||||
| OIDC_OP_USER_ENDPOINT_FORMAT | OIDC endpoint format (AUTO, JWT, JSON) | AUTO |
|
| OIDC_OP_TOKEN_ENDPOINT | OIDC endpoint for token | |
|
||||||
| OIDC_OP_LOGOUT_ENDPOINT | OIDC endpoint for logout | |
|
| OIDC_OP_USER_ENDPOINT | OIDC endpoint for user | |
|
||||||
| OIDC_AUTH_REQUEST_EXTRA_PARAMS | Extra parameters for OIDC request | {} |
|
| OIDC_OP_USER_ENDPOINT_FORMAT | OIDC endpoint format (AUTO, JWT, JSON) | AUTO |
|
||||||
| OIDC_RP_SCOPES | OIDC scopes | openid email |
|
| OIDC_OP_LOGOUT_ENDPOINT | OIDC endpoint for logout | |
|
||||||
| OIDC_USE_NONCE | Use nonce for OIDC | true |
|
| OIDC_AUTH_REQUEST_EXTRA_PARAMS | Extra parameters for OIDC request | {} |
|
||||||
| OIDC_REDIRECT_REQUIRE_HTTPS | Require HTTPS for OIDC | false |
|
| OIDC_RP_SCOPES | OIDC scopes | openid email |
|
||||||
| OIDC_REDIRECT_ALLOWED_HOSTS | Allowed redirect hosts for OIDC | [] |
|
| OIDC_USE_NONCE | Use nonce for OIDC | true |
|
||||||
| OIDC_STORE_ID_TOKEN | Store OIDC ID token | true |
|
| OIDC_REDIRECT_REQUIRE_HTTPS | Require HTTPS for OIDC | false |
|
||||||
| OIDC_REDIRECT_FIELD_NAME | Redirect field for OIDC | returnTo |
|
| OIDC_REDIRECT_ALLOWED_HOSTS | Allowed redirect hosts for OIDC | [] |
|
||||||
| OIDC_USERINFO_FULLNAME_FIELDS | Full name claim from OIDC token | ["given_name", "usual_name"] |
|
| OIDC_STORE_ID_TOKEN | Store OIDC ID token | true |
|
||||||
| OIDC_USERINFO_SHORTNAME_FIELD | Short name claim from OIDC token | given_name |
|
| OIDC_REDIRECT_FIELD_NAME | Redirect field for OIDC | returnTo |
|
||||||
| OIDC_USERINFO_ESSENTIAL_CLAIMS | Required claims from OIDC token | [] |
|
| OIDC_USERINFO_FULLNAME_FIELDS | Full name claim from OIDC token | ["given_name", "usual_name"] |
|
||||||
| OIDC_USE_PKCE | Enable the use of PKCE (Proof Key for Code Exchange) during the OAuth 2.0 authorization code flow. Recommended for enhanced security. | False |
|
| OIDC_USERINFO_SHORTNAME_FIELD | Short name claim from OIDC token | given_name |
|
||||||
| OIDC_PKCE_CODE_CHALLENGE_METHOD | Method used to generate the PKCE code challenge. Common values include S256 and plain. Refer to the mozilla-django-oidc documentation for supported options. | S256 |
|
| OIDC_USERINFO_ESSENTIAL_CLAIMS | Required claims from OIDC token | [] |
|
||||||
| OIDC_PKCE_CODE_VERIFIER_SIZE | Length of the random string used as the PKCE code verifier. Must be an integer between 43 and 128, inclusive. | 64 |
|
| OIDC_USE_PKCE | Enable the use of PKCE (Proof Key for Code Exchange) during the OAuth 2.0 authorization code flow. Recommended for enhanced security. | False |
|
||||||
| LOGIN_REDIRECT_URL | Login redirect URL | |
|
| OIDC_PKCE_CODE_CHALLENGE_METHOD | Method used to generate the PKCE code challenge. Common values include S256 and plain. Refer to the mozilla-django-oidc documentation for supported options. | S256 |
|
||||||
| LOGIN_REDIRECT_URL_FAILURE | Login redirect URL for failure | |
|
| OIDC_PKCE_CODE_VERIFIER_SIZE | Length of the random string used as the PKCE code verifier. Must be an integer between 43 and 128, inclusive. | 64 |
|
||||||
| LOGOUT_REDIRECT_URL | URL to redirect to on logout | |
|
| LOGIN_REDIRECT_URL | Login redirect URL | |
|
||||||
| ALLOW_LOGOUT_GET_METHOD | Allow logout through GET method | true |
|
| LOGIN_REDIRECT_URL_FAILURE | Login redirect URL for failure | |
|
||||||
| LIVEKIT_API_KEY | LiveKit API key | |
|
| LOGOUT_REDIRECT_URL | URL to redirect to on logout | |
|
||||||
| LIVEKIT_API_SECRET | LiveKit API secret | |
|
| ALLOW_LOGOUT_GET_METHOD | Allow logout through GET method | true |
|
||||||
| LIVEKIT_API_URL | LiveKit API URL | |
|
| LIVEKIT_API_KEY | LiveKit API key | |
|
||||||
| LIVEKIT_VERIFY_SSL | Verify SSL for LiveKit connections | true |
|
| LIVEKIT_API_SECRET | LiveKit API secret | |
|
||||||
| LIVEKIT_FORCE_WSS_PROTOCOL | Enables WSS protocol conversion for legacy browser compatibility (Firefox <124, Chrome <125, Edge <125) where HTTPS URLs fail in WebSocket() constructor. | false |
|
| LIVEKIT_API_URL | LiveKit API URL | |
|
||||||
| LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND | Firefox-only connection warmup: pre-calls WebSocket endpoint (expecting 401) to initialize cache, resolving proxy/network connectivity issues. | false |
|
| LIVEKIT_VERIFY_SSL | Verify SSL for LiveKit connections | true |
|
||||||
| RESOURCE_DEFAULT_ACCESS_LEVEL | Default resource access level for rooms | public |
|
| LIVEKIT_FORCE_WSS_PROTOCOL | Enables WSS protocol conversion for legacy browser compatibility (Firefox <124, Chrome <125, Edge <125) where HTTPS URLs fail in WebSocket() constructor. | false |
|
||||||
| ALLOW_UNREGISTERED_ROOMS | Allow usage of unregistered rooms | true |
|
| LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND | Firefox-only connection warmup: pre-calls WebSocket endpoint (expecting 401) to initialize cache, resolving proxy/network connectivity issues. | false |
|
||||||
| ROOM_INACTIVITY_DELETION_DAYS | Days without being started after which a room is purged. Unset to never purge | |
|
| RESOURCE_DEFAULT_ACCESS_LEVEL | Default resource access level for rooms | public |
|
||||||
| RECORDING_ENABLE | Record meeting option | false |
|
| ALLOW_UNREGISTERED_ROOMS | Allow usage of unregistered rooms | true |
|
||||||
| RECORDING_OUTPUT_FOLDER | Folder to store meetings | recordings |
|
| ROOM_INACTIVITY_DELETION_DAYS | Days without being started after which a room is purged. Unset to never purge | |
|
||||||
|
| RECORDING_ENABLE | Record meeting option | false |
|
||||||
|
| RECORDING_OUTPUT_FOLDER | Folder to store meetings | recordings |
|
||||||
| RECORDING_WORKER_CLASSES | Worker classes for recording | {"screen_recording": "core.recording.worker.services.VideoCompositeEgressService","transcript": "core.recording.worker.services.AudioCompositeEgressService"} |
|
| RECORDING_WORKER_CLASSES | Worker classes for recording | {"screen_recording": "core.recording.worker.services.VideoCompositeEgressService","transcript": "core.recording.worker.services.AudioCompositeEgressService"} |
|
||||||
| RECORDING_EXPIRATION_DAYS | Recording expiration in days | |
|
| RECORDING_EXPIRATION_DAYS | Recording expiration in days | |
|
||||||
| RECORDING_MAX_DURATION | Maximum recording duration in milliseconds. Must match LiveKit Egress configuration exactly. | |
|
| RECORDING_MAX_DURATION | Maximum recording duration in milliseconds. Must match LiveKit Egress configuration exactly. | |
|
||||||
| SCREEN_RECORDING_BASE_URL | Screen recording base URL | |
|
| SCREEN_RECORDING_BASE_URL | Screen recording base URL | |
|
||||||
| SUMMARY_SERVICE_ENDPOINT | Summary service endpoint | |
|
| SUMMARY_SERVICE_ENDPOINT | Summary service endpoint | |
|
||||||
| SUMMARY_SERVICE_API_TOKEN | API token for summary service | |
|
| SUMMARY_SERVICE_API_TOKEN | API token for summary service | |
|
||||||
| SIGNUP_NEW_USER_TO_MARKETING_EMAIL | Signup users to marketing emails | false |
|
| SIGNUP_NEW_USER_TO_MARKETING_EMAIL | Signup users to marketing emails | false |
|
||||||
| MARKETING_SERVICE_CLASS | Marketing service class | core.services.marketing.BrevoMarketingService |
|
| MARKETING_SERVICE_CLASS | Marketing service class | core.services.marketing.BrevoMarketingService |
|
||||||
| BREVO_API_KEY | Brevo API key for marketing emails | |
|
| BREVO_API_KEY | Brevo API key for marketing emails | |
|
||||||
| BREVO_API_CONTACT_LIST_IDS | Brevo API contact list IDs | [] |
|
| BREVO_API_CONTACT_LIST_IDS | Brevo API contact list IDs | [] |
|
||||||
| DJANGO_BREVO_API_CONTACT_ATTRIBUTES | Brevo contact attributes | {"VISIO_USER": true} |
|
| DJANGO_BREVO_API_CONTACT_ATTRIBUTES | Brevo contact attributes | {"VISIO_USER": true} |
|
||||||
| BREVO_API_TIMEOUT | Brevo timeout in seconds | 1 |
|
| BREVO_API_TIMEOUT | Brevo timeout in seconds | 1 |
|
||||||
| LOBBY_KEY_PREFIX | Lobby key prefix | room_lobby |
|
| LOBBY_KEY_PREFIX | Lobby key prefix | room_lobby |
|
||||||
| LOBBY_WAITING_TIMEOUT | Lobby waiting timeout in seconds | 3 |
|
| LOBBY_WAITING_TIMEOUT | Lobby waiting timeout in seconds | 3 |
|
||||||
| LOBBY_DENIED_TIMEOUT | Lobby deny timeout in seconds | 5 |
|
| LOBBY_DENIED_TIMEOUT | Lobby deny timeout in seconds | 5 |
|
||||||
| LOBBY_ACCEPTED_TIMEOUT | Lobby accept timeout in seconds | 21600 (6 hours) |
|
| LOBBY_ACCEPTED_TIMEOUT | Lobby accept timeout in seconds | 21600 (6 hours) |
|
||||||
| LOBBY_NOTIFICATION_TYPE | Lobby notification types | participantWaiting |
|
| LOBBY_NOTIFICATION_TYPE | Lobby notification types | participantWaiting |
|
||||||
| LOBBY_COOKIE_NAME | Lobby cookie name | lobbyParticipantId |
|
| LOBBY_COOKIE_NAME | Lobby cookie name | lobbyParticipantId |
|
||||||
| ROOM_CREATION_CALLBACK_CACHE_TIMEOUT | Room creation callback cache timeout | 600 (10 minutes) |
|
| ROOM_CREATION_CALLBACK_CACHE_TIMEOUT | Room creation callback cache timeout | 600 (10 minutes) |
|
||||||
| ROOM_TELEPHONY_ENABLED | Enable SIP telephony feature | false |
|
| ROOM_TELEPHONY_ENABLED | Enable SIP telephony feature | false |
|
||||||
| ROOM_TELEPHONY_PIN_LENGTH | Telephony PIN length | 10 |
|
| ROOM_TELEPHONY_PIN_LENGTH | Telephony PIN length | 10 |
|
||||||
| ROOM_TELEPHONY_PIN_MAX_RETRIES | Telephony PIN maximum retries | 5 |
|
| ROOM_TELEPHONY_PIN_MAX_RETRIES | Telephony PIN maximum retries | 5 |
|
||||||
|
|||||||
+1
-1
@@ -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": [
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
FROM python:3.14.6-slim AS base
|
FROM python:3.14.7-slim AS base
|
||||||
|
|
||||||
# Install system dependencies required by LiveKit, fetching packages over HTTPS only for Bureautix proxy
|
# Install system dependencies required by LiveKit, fetching packages over HTTPS only for Bureautix proxy
|
||||||
RUN sed -i "s|^URIs: http://|URIs: https://|" /etc/apt/sources.list.d/debian.sources \
|
RUN sed -i "s|^URIs: http://|URIs: https://|" /etc/apt/sources.list.d/debian.sources \
|
||||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libglib2.0-0 \
|
libglib2.0-0 \
|
||||||
libgobject-2.0-0 \
|
libgobject-2.0-0 \
|
||||||
|
libpcre2-8-0 \
|
||||||
libssl3t64 \
|
libssl3t64 \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "agents"
|
name = "agents"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"livekit-agents==1.7.0",
|
"livekit-agents==1.7.0",
|
||||||
|
|||||||
Generated
+1
-1
@@ -9,7 +9,7 @@ resolution-markers = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agents"
|
name = "agents"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "boto3" },
|
{ name = "boto3" },
|
||||||
|
|||||||
@@ -20,6 +20,33 @@ class MonitoredUserRateThrottle(MonitoredThrottleMixin, UserRateThrottle):
|
|||||||
"""Throttle for the monitored scoped rate throttle."""
|
"""Throttle for the monitored scoped rate throttle."""
|
||||||
|
|
||||||
|
|
||||||
|
class RoomCreationUserRateThrottle(MonitoredUserRateThrottle):
|
||||||
|
"""Throttle room creation per authenticated user.
|
||||||
|
|
||||||
|
Can be declared at the viewset level: every action other than "create"
|
||||||
|
is left unthrottled, so the same class can be reused on any viewset
|
||||||
|
exposing a room creation endpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
scope = "room_creation"
|
||||||
|
|
||||||
|
def get_cache_key(self, request, view):
|
||||||
|
"""Throttle only room creations."""
|
||||||
|
if getattr(view, "action", None) != "create":
|
||||||
|
return None
|
||||||
|
return super().get_cache_key(request, view)
|
||||||
|
|
||||||
|
|
||||||
|
class RoomCreationDailyUserRateThrottle(RoomCreationUserRateThrottle):
|
||||||
|
"""Cap room creation per authenticated user over a day.
|
||||||
|
|
||||||
|
Complements the short-term RoomCreationUserRateThrottle, which absorbs
|
||||||
|
bursts but lets a user steadily create rooms over hours or days.
|
||||||
|
"""
|
||||||
|
|
||||||
|
scope = "room_creation_daily"
|
||||||
|
|
||||||
|
|
||||||
class RequestEntryAuthenticatedUserRateThrottle(MonitoredUserRateThrottle):
|
class RequestEntryAuthenticatedUserRateThrottle(MonitoredUserRateThrottle):
|
||||||
"""Throttle authenticated user requesting room entry"""
|
"""Throttle authenticated user requesting room entry"""
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,10 @@ class RoomViewSet(
|
|||||||
permission_classes = [permissions.RoomPermissions]
|
permission_classes = [permissions.RoomPermissions]
|
||||||
queryset = models.Room.objects.all()
|
queryset = models.Room.objects.all()
|
||||||
serializer_class = serializers.RoomSerializer
|
serializer_class = serializers.RoomSerializer
|
||||||
|
throttle_classes = [
|
||||||
|
throttling.RoomCreationUserRateThrottle,
|
||||||
|
throttling.RoomCreationDailyUserRateThrottle,
|
||||||
|
]
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""Allow getting a room by its slug."""
|
"""Allow getting a room by its slug."""
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ from django.core.cache import cache
|
|||||||
import pytest
|
import pytest
|
||||||
from rest_framework.test import APIClient
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from ...api.throttling import (
|
||||||
|
RoomCreationDailyUserRateThrottle,
|
||||||
|
RoomCreationUserRateThrottle,
|
||||||
|
)
|
||||||
from ...factories import RoomFactory, UserFactory
|
from ...factories import RoomFactory, UserFactory
|
||||||
from ...models import Room, RoomAccessLevel
|
from ...models import Room, RoomAccessLevel
|
||||||
|
|
||||||
@@ -312,3 +316,145 @@ def test_api_rooms_create_authenticated_blank_user_default_access_level():
|
|||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
room = Room.objects.get()
|
room = Room.objects.get()
|
||||||
assert room.access_level == settings.RESOURCE_DEFAULT_ACCESS_LEVEL
|
assert room.access_level == settings.RESOURCE_DEFAULT_ACCESS_LEVEL
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def room_creation_throttle(monkeypatch):
|
||||||
|
"""Lower the room creation rate for the duration of a test."""
|
||||||
|
monkeypatch.setitem(
|
||||||
|
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"], "room_creation", "2/minute"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_throttled(room_creation_throttle):
|
||||||
|
"""Excess requests are rejected and create no room."""
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
|
||||||
|
for index in range(2):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Blocked room"})
|
||||||
|
assert response.status_code == 429
|
||||||
|
assert 0 < int(response["Retry-After"]) <= 60
|
||||||
|
assert Room.objects.count() == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_throttle_per_user(room_creation_throttle):
|
||||||
|
"""Users sharing an IP have independent creation limits."""
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
for index in range(2):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"First user room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Blocked room"})
|
||||||
|
assert response.status_code == 429
|
||||||
|
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Second user room"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_throttle_does_not_limit_other_actions(room_creation_throttle):
|
||||||
|
"""Exhausting creation capacity leaves listing and updating available."""
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
for index in range(2):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
room_id = response.json()["id"]
|
||||||
|
|
||||||
|
assert client.post("/api/v1.0/rooms/", {"name": "Blocked room"}).status_code == 429
|
||||||
|
assert client.get("/api/v1.0/rooms/").status_code == 200
|
||||||
|
assert (
|
||||||
|
client.patch(
|
||||||
|
f"/api/v1.0/rooms/{room_id}/", {"name": "Renamed room"}
|
||||||
|
).status_code
|
||||||
|
== 200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def daily_room_creation_throttle(monkeypatch):
|
||||||
|
"""Use a tiny daily cap, a loose burst limit and a controllable clock.
|
||||||
|
|
||||||
|
Rates are patched with monkeypatch.setitem so they are restored after the
|
||||||
|
test. Returns a one-item list holding the current fake timestamp.
|
||||||
|
"""
|
||||||
|
rates = RoomCreationDailyUserRateThrottle.THROTTLE_RATES
|
||||||
|
monkeypatch.setitem(rates, "room_creation", "100/minute")
|
||||||
|
monkeypatch.setitem(rates, "room_creation_daily", "3/day")
|
||||||
|
now = [1_000_000.0]
|
||||||
|
monkeypatch.setattr(RoomCreationUserRateThrottle, "timer", lambda self: now[0])
|
||||||
|
return now
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_daily_throttled(daily_room_creation_throttle):
|
||||||
|
"""The daily cap still applies once the short-term window has elapsed."""
|
||||||
|
now = daily_room_creation_throttle
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
|
||||||
|
for index in range(3):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
now[0] += 120 # Spread creations beyond the short-term window.
|
||||||
|
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Blocked room"})
|
||||||
|
assert response.status_code == 429
|
||||||
|
assert int(response["Retry-After"]) > 60
|
||||||
|
assert Room.objects.count() == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_daily_throttle_resets(daily_room_creation_throttle):
|
||||||
|
"""Room creation is allowed again once a day has passed."""
|
||||||
|
now = daily_room_creation_throttle
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
|
||||||
|
for index in range(3):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Blocked room"})
|
||||||
|
assert response.status_code == 429
|
||||||
|
|
||||||
|
now[0] += 24 * 60 * 60 + 1
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Next day room"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_daily_throttle_per_user(daily_room_creation_throttle):
|
||||||
|
"""Each user has its own daily cap."""
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
for index in range(3):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
assert client.post("/api/v1.0/rooms/", {"name": "Blocked"}).status_code == 429
|
||||||
|
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": "Other user room"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_create_daily_throttle_does_not_limit_other_actions(
|
||||||
|
daily_room_creation_throttle,
|
||||||
|
):
|
||||||
|
"""Reaching the daily cap leaves listing and updating available."""
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(UserFactory())
|
||||||
|
for index in range(3):
|
||||||
|
response = client.post("/api/v1.0/rooms/", {"name": f"Room {index}"})
|
||||||
|
assert response.status_code == 201
|
||||||
|
room_id = response.json()["id"]
|
||||||
|
|
||||||
|
assert client.post("/api/v1.0/rooms/", {"name": "Blocked"}).status_code == 429
|
||||||
|
assert client.get("/api/v1.0/rooms/").status_code == 200
|
||||||
|
response = client.patch(f"/api/v1.0/rooms/{room_id}/", {"name": "Renamed"})
|
||||||
|
assert response.status_code == 200
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -361,6 +361,16 @@ class Base(Configuration):
|
|||||||
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
|
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
|
||||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
"DEFAULT_THROTTLE_RATES": {
|
"DEFAULT_THROTTLE_RATES": {
|
||||||
|
"room_creation": values.Value(
|
||||||
|
default="50/minute",
|
||||||
|
environ_name="ROOM_CREATION_THROTTLE_RATES",
|
||||||
|
environ_prefix=None,
|
||||||
|
),
|
||||||
|
"room_creation_daily": values.Value(
|
||||||
|
default="1000/day",
|
||||||
|
environ_name="ROOM_CREATION_DAILY_THROTTLE_RATES",
|
||||||
|
environ_prefix=None,
|
||||||
|
),
|
||||||
"request_entry": values.Value(
|
"request_entry": values.Value(
|
||||||
default="150/minute",
|
default="150/minute",
|
||||||
environ_name="REQUEST_ENTRY_THROTTLE_RATES",
|
environ_name="REQUEST_ENTRY_THROTTLE_RATES",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ build-backend = "uv_build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "meet"
|
name = "meet"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
@@ -40,7 +40,7 @@ dependencies = [
|
|||||||
"django-storages[s3]==1.14.6",
|
"django-storages[s3]==1.14.6",
|
||||||
"django-timezone-field>=5.1",
|
"django-timezone-field>=5.1",
|
||||||
"django-pydantic-field==0.5.4",
|
"django-pydantic-field==0.5.4",
|
||||||
"django==5.2.16",
|
"django==5.2.17",
|
||||||
"djangorestframework==3.18.0",
|
"djangorestframework==3.18.0",
|
||||||
"drf_spectacular==0.30.0",
|
"drf_spectacular==0.30.0",
|
||||||
"dockerflow==2026.3.4",
|
"dockerflow==2026.3.4",
|
||||||
@@ -62,7 +62,7 @@ dependencies = [
|
|||||||
"mozilla-django-oidc==5.0.2",
|
"mozilla-django-oidc==5.0.2",
|
||||||
"livekit-api==1.2.0",
|
"livekit-api==1.2.0",
|
||||||
"aiohttp==3.14.3",
|
"aiohttp==3.14.3",
|
||||||
"urllib3==2.7.0",
|
"urllib3==2.8.0",
|
||||||
"phonenumbers==9.0.37",
|
"phonenumbers==9.0.37",
|
||||||
"cryptography==50.0.1", # CVE-2026-69247
|
"cryptography==50.0.1", # CVE-2026-69247
|
||||||
]
|
]
|
||||||
|
|||||||
Generated
+9
-9
@@ -700,16 +700,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "5.2.16"
|
version = "5.2.17"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asgiref" },
|
{ name = "asgiref" },
|
||||||
{ name = "sqlparse" },
|
{ name = "sqlparse" },
|
||||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a9/26/889449d521ae508b26de715954faecd8bcf3f740affb81b2d146a83b42a5/django-5.2.16.tar.gz", hash = "sha256:59ea02020c3136fce14bef0bbece21a10a4febef5eed1c51c22ae468efa22200", size = 10890894, upload-time = "2026-07-07T13:52:17.005Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/d5/d8/43e9d000519adceb189620b6869ff88031e046df91c2e9da72f8f6918399/django-5.2.17.tar.gz", hash = "sha256:9d4d93be539a18ab80d058eb515900e10951e04c537c5a6b394fc49528d3251f", size = 10889740, upload-time = "2026-08-04T15:04:03.173Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/13/1e5e3e4c15dcecb04281b3cb2a46a4670e1cef131068e202f6040df19224/django-5.2.16-py3-none-any.whl", hash = "sha256:04f354bf9d807a86ad1a8392fe3808d362358a8eafc322848e0e43e59b24371d", size = 8311943, upload-time = "2026-07-07T13:52:11.223Z" },
|
{ url = "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl", hash = "sha256:f04fb3b36ee119e1af4fa1d397d5fd6cf12700f49321e84d4f4c642c5b1973db", size = 8315563, upload-time = "2026-08-04T15:03:59.1Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1297,7 +1297,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "meet"
|
name = "meet"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiohttp" },
|
{ name = "aiohttp" },
|
||||||
@@ -1372,7 +1372,7 @@ requires-dist = [
|
|||||||
{ name = "celery", extras = ["redis"], specifier = "==5.6.3" },
|
{ name = "celery", extras = ["redis"], specifier = "==5.6.3" },
|
||||||
{ name = "cryptography", specifier = "==50.0.1" },
|
{ name = "cryptography", specifier = "==50.0.1" },
|
||||||
{ name = "dj-database-url", specifier = "==3.1.2" },
|
{ name = "dj-database-url", specifier = "==3.1.2" },
|
||||||
{ name = "django", specifier = "==5.2.16" },
|
{ name = "django", specifier = "==5.2.17" },
|
||||||
{ name = "django-configurations", specifier = "==2.5.1" },
|
{ name = "django-configurations", specifier = "==2.5.1" },
|
||||||
{ name = "django-cors-headers", specifier = "==4.9.0" },
|
{ name = "django-cors-headers", specifier = "==4.9.0" },
|
||||||
{ name = "django-countries", specifier = "==9.0.0" },
|
{ name = "django-countries", specifier = "==9.0.0" },
|
||||||
@@ -1404,7 +1404,7 @@ requires-dist = [
|
|||||||
{ name = "redis", specifier = "==5.2.1" },
|
{ name = "redis", specifier = "==5.2.1" },
|
||||||
{ name = "requests", specifier = "==2.34.2" },
|
{ name = "requests", specifier = "==2.34.2" },
|
||||||
{ name = "sentry-sdk", specifier = "==2.68.1" },
|
{ name = "sentry-sdk", specifier = "==2.68.1" },
|
||||||
{ name = "urllib3", specifier = "==2.7.0" },
|
{ name = "urllib3", specifier = "==2.8.0" },
|
||||||
{ name = "whitenoise", specifier = "==6.12.0" },
|
{ name = "whitenoise", specifier = "==6.12.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2529,11 +2529,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.7.0"
|
version = "2.8.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
{ url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.3.0",
|
"@fontsource-variable/atkinson-hyperlegible-next": "5.3.0",
|
||||||
"@fontsource-variable/lexend": "5.3.0",
|
"@fontsource-variable/lexend": "5.3.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "panda codegen && vite",
|
"dev": "panda codegen && vite",
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ export const ScreenRecordingSidePanel = () => {
|
|||||||
FeatureFlags.ScreenRecording
|
FeatureFlags.ScreenRecording
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const hasTranscriptAccess = useHasRecordingAccess(
|
||||||
|
RecordingMode.Transcript,
|
||||||
|
FeatureFlags.Transcript
|
||||||
|
)
|
||||||
const { notifyParticipants } = useNotifyParticipants()
|
const { notifyParticipants } = useNotifyParticipants()
|
||||||
const { selectedLanguageKey, isLanguageSetToAuto } =
|
const { selectedLanguageKey, isLanguageSetToAuto } =
|
||||||
useTranscriptionLanguage()
|
useTranscriptionLanguage()
|
||||||
@@ -88,7 +92,7 @@ export const ScreenRecordingSidePanel = () => {
|
|||||||
...(!isLanguageSetToAuto && {
|
...(!isLanguageSetToAuto && {
|
||||||
language: selectedLanguageKey,
|
language: selectedLanguageKey,
|
||||||
}),
|
}),
|
||||||
...(includeTranscript && { transcribe: true }),
|
...(includeTranscript && hasTranscriptAccess && { transcribe: true }),
|
||||||
}
|
}
|
||||||
|
|
||||||
await startRecording({
|
await startRecording({
|
||||||
@@ -182,24 +186,26 @@ export const ScreenRecordingSidePanel = () => {
|
|||||||
<RowWrapper iconName="mail" position="last">
|
<RowWrapper iconName="mail" position="last">
|
||||||
<Text variant="sm">{t('details.receiver')}</Text>
|
<Text variant="sm">{t('details.receiver')}</Text>
|
||||||
</RowWrapper>
|
</RowWrapper>
|
||||||
|
{hasTranscriptAccess && (
|
||||||
<div className={css({ height: '15px' })} />
|
<>
|
||||||
|
<div className={css({ height: '15px' })} />
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
size="sm"
|
size="sm"
|
||||||
isSelected={includeTranscript}
|
isSelected={includeTranscript}
|
||||||
onChange={setIncludeTranscript}
|
onChange={setIncludeTranscript}
|
||||||
isDisabled={statuses.isActive || isPendingToStart}
|
isDisabled={statuses.isActive || isPendingToStart}
|
||||||
>
|
>
|
||||||
<Text variant="sm">{t('details.transcription')}</Text>
|
<Text variant="sm">{t('details.transcription')}</Text>
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
<ControlsButton
|
<ControlsButton
|
||||||
i18nKeyPrefix={keyPrefix}
|
i18nKeyPrefix={keyPrefix}
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ export const TranscriptSidePanel = () => {
|
|||||||
FeatureFlags.Transcript
|
FeatureFlags.Transcript
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const hasScreenRecordingAccess = useHasRecordingAccess(
|
||||||
|
RecordingMode.ScreenRecording,
|
||||||
|
FeatureFlags.ScreenRecording
|
||||||
|
)
|
||||||
const hasFeatureWithoutAdminRights = useHasFeatureWithoutAdminRights(
|
const hasFeatureWithoutAdminRights = useHasFeatureWithoutAdminRights(
|
||||||
RecordingMode.Transcript,
|
RecordingMode.Transcript,
|
||||||
FeatureFlags.Transcript
|
FeatureFlags.Transcript
|
||||||
@@ -97,7 +101,9 @@ export const TranscriptSidePanel = () => {
|
|||||||
room.localParticipant
|
room.localParticipant
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
const recordingMode = includeScreenRecording
|
const withScreenRecording =
|
||||||
|
includeScreenRecording && hasScreenRecordingAccess
|
||||||
|
const recordingMode = withScreenRecording
|
||||||
? RecordingMode.ScreenRecording
|
? RecordingMode.ScreenRecording
|
||||||
: RecordingMode.Transcript
|
: RecordingMode.Transcript
|
||||||
|
|
||||||
@@ -105,7 +111,7 @@ export const TranscriptSidePanel = () => {
|
|||||||
...(!isLanguageSetToAuto && {
|
...(!isLanguageSetToAuto && {
|
||||||
language: selectedLanguageKey,
|
language: selectedLanguageKey,
|
||||||
}),
|
}),
|
||||||
...(includeScreenRecording && {
|
...(withScreenRecording && {
|
||||||
transcribe: true,
|
transcribe: true,
|
||||||
original_mode: RecordingMode.Transcript,
|
original_mode: RecordingMode.Transcript,
|
||||||
}),
|
}),
|
||||||
@@ -122,7 +128,7 @@ export const TranscriptSidePanel = () => {
|
|||||||
type: NotificationType.TranscriptionStarted,
|
type: NotificationType.TranscriptionStarted,
|
||||||
})
|
})
|
||||||
captureEvent('transcript-started', {
|
captureEvent('transcript-started', {
|
||||||
includeScreenRecording: includeScreenRecording,
|
includeScreenRecording: withScreenRecording,
|
||||||
language: selectedLanguageKey,
|
language: selectedLanguageKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -234,22 +240,26 @@ export const TranscriptSidePanel = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Text>
|
</Text>
|
||||||
</RowWrapper>
|
</RowWrapper>
|
||||||
<div className={css({ height: '15px' })} />
|
{hasScreenRecordingAccess && (
|
||||||
<div
|
<>
|
||||||
className={css({
|
<div className={css({ height: '15px' })} />
|
||||||
width: '100%',
|
<div
|
||||||
marginLeft: '20px',
|
className={css({
|
||||||
})}
|
width: '100%',
|
||||||
>
|
marginLeft: '20px',
|
||||||
<Checkbox
|
})}
|
||||||
size="sm"
|
>
|
||||||
isSelected={includeScreenRecording}
|
<Checkbox
|
||||||
onChange={setIncludeScreenRecording}
|
size="sm"
|
||||||
isDisabled={statuses.isActive || isPendingToStart}
|
isSelected={includeScreenRecording}
|
||||||
>
|
onChange={setIncludeScreenRecording}
|
||||||
<Text variant="sm">{t('details.recording')}</Text>
|
isDisabled={statuses.isActive || isPendingToStart}
|
||||||
</Checkbox>
|
>
|
||||||
</div>
|
<Text variant="sm">{t('details.recording')}</Text>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
<ControlsButton
|
<ControlsButton
|
||||||
i18nKeyPrefix={keyPrefix}
|
i18nKeyPrefix={keyPrefix}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,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/"
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@html-to/text-cli": "0.6.1",
|
"@html-to/text-cli": "0.6.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"description": "An util to generate html and text django's templates from mjml templates",
|
"description": "An util to generate html and text django's templates from mjml templates",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -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": {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./library",
|
"./library",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.32.1",
|
"version": "1.33.0",
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "summary"
|
name = "summary"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastapi[standard]>=0.105.0",
|
"fastapi[standard]>=0.105.0",
|
||||||
|
|||||||
Generated
+1
-1
@@ -1484,7 +1484,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "summary"
|
name = "summary"
|
||||||
version = "1.32.1"
|
version = "1.33.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "boto3" },
|
{ name = "boto3" },
|
||||||
|
|||||||
Reference in New Issue
Block a user