diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2f855157e..9f75c0dc1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -20,6 +20,10 @@ concurrency: jobs: build: runs-on: ubuntu-latest + env: + # Install from the committed lockfile; never re-resolve (see pyproject + # [tool.uv] exclude-newer cooling window). + UV_FROZEN: "1" steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/locale-sync.yml b/.github/workflows/locale-sync.yml index 1fbd45652..e515425d5 100644 --- a/.github/workflows/locale-sync.yml +++ b/.github/workflows/locale-sync.yml @@ -14,6 +14,10 @@ permissions: jobs: sync-locales: runs-on: ubuntu-latest + env: + # Install from the committed lockfile; never re-resolve (see pyproject + # [tool.uv] exclude-newer cooling window). + UV_FROZEN: "1" steps: - name: Generate GitHub App Token id: app-token diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 64d1c5248..1bd8ca7a1 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -13,6 +13,10 @@ jobs: env: PRODUCTION: false + # Install from the committed lockfile; never re-resolve. The rolling + # `exclude-newer` cooling window (pyproject [tool.uv]) would otherwise make + # every uv command re-resolve and fail on in-window pins. + UV_FROZEN: "1" strategy: fail-fast: true diff --git a/Taskfile.yml b/Taskfile.yml index 716e3e7b3..1ea67f346 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,6 +7,10 @@ env: DEFAULT_GROUP: Home DEFAULT_HOUSEHOLD: Family PRODUCTION: false + # Install from the committed lockfile; never re-resolve. Required because the + # rolling `exclude-newer` cooling window (pyproject [tool.uv]) would otherwise + # make every `uv run`/`uv sync` re-resolve and fail on in-window pins. + UV_FROZEN: "1" API_PORT: 9000 API_DOCS: True TOKEN_TIME: 256 # hours diff --git a/docker/Dockerfile b/docker/Dockerfile index 395c0e402..1bc96245e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -52,6 +52,11 @@ RUN apt-get update \ RUN pip install uv +# Install from the committed lockfile; never re-resolve. The rolling +# `exclude-newer` cooling window (pyproject [tool.uv]) would otherwise make +# `uv export` below re-resolve and fail on in-window pins. +ENV UV_FROZEN=1 + WORKDIR /mealie # copy project files here to ensure they will be cached. diff --git a/pyproject.toml b/pyproject.toml index ec8b540c8..f4744dadf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -178,3 +178,7 @@ max-complexity = 24 # Default is 10. [tool.uv] add-bounds = "exact" +# Cooling period: ignore package releases newer than 5 days to mitigate +# supply-chain attacks (compromised releases are usually caught and yanked +# within days). Evaluated at resolve time as a rolling window. +exclude-newer = "5 days" diff --git a/renovate.json b/renovate.json index beef4abbd..275630bb3 100644 --- a/renovate.json +++ b/renovate.json @@ -12,6 +12,8 @@ "extends": [ "config:recommended" ], + "minimumReleaseAge": "5 days", + "internalChecksFilter": "strict", "addLabels": [ "dependencies" ], @@ -51,8 +53,7 @@ ], "automerge": true, "automergeType": "pr", - "automergeStrategy": "squash", - "minimumReleaseAge": "5 days" + "automergeStrategy": "squash" }, { "description": "Auto-merge Docker digest and patch updates", @@ -66,8 +67,7 @@ ], "automerge": true, "automergeType": "pr", - "automergeStrategy": "squash", - "minimumReleaseAge": "5 days" + "automergeStrategy": "squash" } ] }