From d90b00d7ac9fe3207f571e023f1ef5042fc5aa22 Mon Sep 17 00:00:00 2001 From: Chris Farhood <3+cpfarhood@noreply.git.farh.net> Date: Mon, 25 May 2026 21:47:10 +0000 Subject: [PATCH 1/9] Add .mcp.json --- .mcp.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .mcp.json diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..6efc1ca --- /dev/null +++ b/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "gitea": { + "type": "http", + "url": "https://git-mcp.farh.net/mcp", + "headers": { + "Authorization": "Bearer ${GITEA_TOKEN}" + } + } + } +} From fb0bb0102c2dc26e86ac2304816f34865b9cd18a Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Thu, 28 May 2026 18:50:53 +0000 Subject: [PATCH 2/9] fix(receiptwitness): pool DB engine and Redis client to prevent connection exhaustion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit email_worker calls get_async_session_factory() inside every resolve_user() call, which creates a brand-new async engine (and thus a brand-new connection pool) on every message. In a tight consumer loop processing 5 messages per batch, this rapidly exhausts DragonflyDB/Postgres connection limits and manifests as ConnectionResetError. Fix: cache the async engine in a module-level dict keyed by URL in cartsnitch_common.database:get_async_engine(), matching the pattern already used in receiptwitness:events.py for the Redis connection pool. Also add pool_size=10, max_overflow=20, pool_pre_ping=True for 健壮连接管理. Similarly, receiptwitness/queue/email.py:get_redis() was creating a new Redis connection on every call with no pooling. Share a ConnectionPool (max_connections=30) across all get_redis() callers. Fixes CAR-1078 Co-Authored-By: Paperclip --- common/src/cartsnitch_common/database.py | 27 +++++++++++++++--- .../src/receiptwitness/queue/email.py | 28 +++++++++++++++---- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/common/src/cartsnitch_common/database.py b/common/src/cartsnitch_common/database.py index 76a4f35..ec27b6c 100644 --- a/common/src/cartsnitch_common/database.py +++ b/common/src/cartsnitch_common/database.py @@ -1,17 +1,36 @@ """Database engine and session factories for sync and async usage.""" from collections.abc import AsyncGenerator, Generator +from typing import TYPE_CHECKING from sqlalchemy import create_engine -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.orm import Session, sessionmaker from cartsnitch_common.config import settings +if TYPE_CHECKING: + from sqlalchemy.engine import Engine -def get_async_engine(url: str | None = None): - """Create an async SQLAlchemy engine.""" - return create_async_engine(url or settings.database_url, echo=settings.debug) +# Module-level async engine cache — one engine per unique URL, shared across all callers. +# This prevents pool exhaustion in high-throughput workers (e.g. email-worker hitting +# DragonflyDB/Postgres repeatedly per message). pool_size=10, max_overflow=20 gives +# headroom for bursts while capping max connections at 30 per URL. +_async_engine_cache: dict[str, "AsyncEngine"] = {} + + +def get_async_engine(url: str | None = None) -> "AsyncEngine": + """Get or create a cached async engine for the given URL.""" + target = url or settings.database_url + if target not in _async_engine_cache: + _async_engine_cache[target] = create_async_engine( + target, + echo=settings.debug, + pool_size=10, + max_overflow=20, + pool_pre_ping=True, + ) + return _async_engine_cache[target] def get_sync_engine(url: str | None = None): diff --git a/receiptwitness/src/receiptwitness/queue/email.py b/receiptwitness/src/receiptwitness/queue/email.py index c76148e..28ff456 100644 --- a/receiptwitness/src/receiptwitness/queue/email.py +++ b/receiptwitness/src/receiptwitness/queue/email.py @@ -16,6 +16,29 @@ logger = logging.getLogger(__name__) STREAM_KEY = "email:receipts" CONSUMER_GROUP = "email-workers" +# Module-level Redis/DragonflyDB connection pool — shared across all worker calls. +# Without pooling, each call to get_redis() opens a new TCP connection. In a tight +# consumer loop this causes ConnectionResetError when DragonflyDB's connection limit +# is hit under load. max_connections=30 (10 base + 20 overflow) mirrors the engine pool. +_redis_pool: aioredis.ConnectionPool | None = None + + +def _get_redis_pool() -> aioredis.ConnectionPool: + """Get or create the shared DragonflyDB connection pool.""" + global _redis_pool + if _redis_pool is None: + _redis_pool = aioredis.ConnectionPool.from_url( + settings.redis_url, + decode_responses=True, + max_connections=30, + ) + return _redis_pool + + +async def get_redis() -> aioredis.Redis: + """Get async Redis/DragonflyDB client backed by a shared connection pool.""" + return aioredis.Redis(connection_pool=_get_redis_pool()) + @dataclass class EmailJob: @@ -31,11 +54,6 @@ class EmailJob: message_id: str # from email provider, for dedup -async def get_redis() -> aioredis.Redis: - """Get async Redis/DragonflyDB client.""" - return cast(aioredis.Redis, aioredis.from_url(settings.redis_url, decode_responses=True)) - - async def ensure_consumer_group(client: aioredis.Redis) -> None: """Create consumer group if it does not exist.""" try: From a7a55bbf7994148a64ebe29c03e5111fa6e9bb89 Mon Sep 17 00:00:00 2001 From: Barcode Betty Date: Wed, 3 Jun 2026 11:41:19 +0000 Subject: [PATCH 3/9] fix(ci): unblock dev PR #271 CI - Remove .mcp.json (scope creep, unrelated to CAR-1078) - Bump vitest to ^4.1.8 (fixes GHSA-5xrq-8626-4rwp critical) - Run npm audit fix for non-breaking vulns - Pin actions/checkout and actions/setup-node to commit SHAs in .gitea/workflows/ci.yml to force a clean cache fetch on the act runner (workaround for corrupted /root/.cache/act cache) Refs CAR-1162, CAR-1122, CAR-1078 --- .gitea/workflows/ci.yml | 32 +-- .mcp.json | 11 - package-lock.json | 536 +++++++++++++++++----------------------- package.json | 2 +- 4 files changed, 238 insertions(+), 343 deletions(-) delete mode 100644 .mcp.json diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index e26c8c9..99b75fa 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -26,8 +26,8 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: "20" cache: npm @@ -40,8 +40,8 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: "20" cache: npm @@ -52,8 +52,8 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: "20" cache: npm @@ -64,8 +64,8 @@ jobs: e2e: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: "20" cache: npm @@ -77,8 +77,8 @@ jobs: runs-on: ubuntu-latest needs: [test] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version: "20" cache: npm @@ -106,7 +106,7 @@ jobs: calver_tag: ${{ steps.calver.outputs.version }} sha_tag: sha-${{ github.sha }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: fetch-depth: 0 @@ -202,7 +202,7 @@ jobs: calver_tag: ${{ steps.calver.outputs.version }} sha_tag: sha-${{ github.sha }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: fetch-depth: 0 @@ -290,7 +290,7 @@ jobs: calver_tag: ${{ steps.calver.outputs.version }} sha_tag: sha-${{ github.sha }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: fetch-depth: 0 @@ -378,7 +378,7 @@ jobs: calver_tag: ${{ steps.calver.outputs.version }} sha_tag: sha-${{ github.sha }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: fetch-depth: 0 @@ -464,7 +464,7 @@ jobs: if: always() && !cancelled() && github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main') steps: - name: Checkout infra repo - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: repository: cartsnitch/infra token: ${{ secrets.REGISTRY_TOKEN }} @@ -554,7 +554,7 @@ jobs: if: always() && !cancelled() && github.event_name == 'push' && (github.ref == 'refs/heads/uat' || github.ref == 'refs/heads/main') steps: - name: Checkout infra repo - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: repository: cartsnitch/infra token: ${{ secrets.REGISTRY_TOKEN }} diff --git a/.mcp.json b/.mcp.json deleted file mode 100644 index 6efc1ca..0000000 --- a/.mcp.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "mcpServers": { - "gitea": { - "type": "http", - "url": "https://git-mcp.farh.net/mcp", - "headers": { - "Authorization": "Bearer ${GITEA_TOKEN}" - } - } - } -} diff --git a/package-lock.json b/package-lock.json index c0a67c2..4d83904 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "typescript-eslint": "^8.56.1", "vite": "^6.4.2", "vite-plugin-pwa": "^0.21.2", - "vitest": "^3.2.4" + "vitest": "^4.1.8" } }, "node_modules/@adobe/css-tools": { @@ -1641,9 +1641,9 @@ } }, "node_modules/@better-auth/core": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.5.6.tgz", - "integrity": "sha512-Ez9DZdIMFyxHremmoLz1emFPGNQomDC1jqqBPnZ6Ci+6TiGN3R9w/Y03cJn6I8r1ycKgOzeVMZtJ/erOZ27Gsw==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.14.tgz", + "integrity": "sha512-12cA7tnR4Wyb3nLpPmeq/Id7QNB+4OhjbzuX7sIhqglgXGjyT5iiNpe2lx/8FF532sHC450Yx1850salCYbkzw==", "license": "MIT", "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", @@ -1651,30 +1651,33 @@ "zod": "^4.3.6" }, "peerDependencies": { - "@better-auth/utils": "0.3.1", + "@better-auth/utils": "0.4.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "@opentelemetry/api": "^1.9.0", - "better-call": "1.3.2", + "better-call": "1.3.5", "jose": "^6.1.0", - "kysely": "^0.28.5", + "kysely": "^0.28.5 || ^0.29.0", "nanostores": "^1.0.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { "optional": true + }, + "@opentelemetry/api": { + "optional": true } } }, "node_modules/@better-auth/kysely-adapter": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.5.6.tgz", - "integrity": "sha512-Fnf+h8WVKtw6lEOmVmiVVzDf3shJtM60AYf9XTnbdCeUd6MxN/KnaJZpkgtYnRs7a+nwtkVB+fg4lGETebGFXQ==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.6.14.tgz", + "integrity": "sha512-A2+381gYADuZpgd98XQ39bnxLzbT03wnnDmSQIXp7XcE3hF093mGMk6rxlAhENVHH7JL2B0Tv2la2o6n+6ppyQ==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/utils": "^0.3.0", - "kysely": "^0.27.0 || ^0.28.0" + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1", + "kysely": "^0.28.17 || ^0.29.0" }, "peerDependenciesMeta": { "kysely": { @@ -1683,23 +1686,23 @@ } }, "node_modules/@better-auth/memory-adapter": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.5.6.tgz", - "integrity": "sha512-rS7ZsrIl5uvloUgNN0u9LOZJMMXnsZXVdUZ3MrTBKWM2KpoJjzPr9yN3Szyma5+0V7SltnzSGHPkYj2bEzzmlA==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.6.14.tgz", + "integrity": "sha512-frtBTozi8qsBlypxp33dkiIZT2IOMvix3oh2qTTcBkK11ISsRSTUUadl7DbwXri2AEoooShsH6PSAput920J3Q==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/utils": "^0.3.0" + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1" } }, "node_modules/@better-auth/mongo-adapter": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.5.6.tgz", - "integrity": "sha512-6+M3MS2mor8fTUV3EI1FBLP0cs6QfbN+Ovx9+XxR/GdfKIBoNFzmPEPRbdGt+ft6PvrITsUm+T70+kkHgVSP6w==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.6.14.tgz", + "integrity": "sha512-meaZx712k9c0Cl6urwYZRNa3mAy3/leaYiSNt+hVaCOEPlgTDxzmYMNACvTTYXgh4eCpDVf5G7ZMEYBtejKQdw==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/utils": "^0.3.0", + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1", "mongodb": "^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { @@ -1709,13 +1712,13 @@ } }, "node_modules/@better-auth/prisma-adapter": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.5.6.tgz", - "integrity": "sha512-UxY9vQJs1Tt+O+T2YQnseDMlWmUSQvFZSBb5YiFRg7zcm+TEzujh4iX2/csA0YiZptLheovIuVWTP9nriewEBA==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.6.14.tgz", + "integrity": "sha512-9b9wSqhCthMmOYo0QdX+N/cOv+fNck/JE5CZQuuWwEJl5QeoYhCZesXjts5VfLAPMIf6vKw3QNBrn0SVMXXi2Q==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/utils": "^0.3.0", + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, @@ -1729,23 +1732,24 @@ } }, "node_modules/@better-auth/telemetry": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.5.6.tgz", - "integrity": "sha512-yXC7NSxnIFlxDkGdpD7KA+J9nqIQAPCJKe77GoaC5bWoe/DALo1MYorZfTgOafS7wrslNtsPT4feV/LJi1ubqQ==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.6.14.tgz", + "integrity": "sha512-ALi3cEx5eyrFY+TeAdhc1uq8FqJyGvzgvIo7GQZOqGqLZxHY9nte44WN++jBFGJJbsW3e4cgLj8dQK291s6wWQ==", "license": "MIT", - "dependencies": { - "@better-auth/utils": "0.3.1", - "@better-fetch/fetch": "1.1.21" - }, "peerDependencies": { - "@better-auth/core": "1.5.6" + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1", + "@better-fetch/fetch": "1.1.21" } }, "node_modules/@better-auth/utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.1.tgz", - "integrity": "sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg==", - "license": "MIT" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.1.tgz", + "integrity": "sha512-SZBPRPF3z0nBvE5ygOkxae35wnnXPRShmqFo78S+qslLeFoPu/pMgnXAuNKFMMybac3tiLaVg1e3MQW5MC+1iA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.0.1" + } }, "node_modules/@better-fetch/fetch": { "version": "1.1.21", @@ -2771,20 +2775,10 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", - "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -4214,59 +4208,87 @@ } }, "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", "devOptional": true, "license": "MIT", "dependencies": { + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "node_modules/@vitest/mocker": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", "devOptional": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^2.0.0" + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", "devOptional": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.4", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "magic-string": "^0.30.17", + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", "pathe": "^2.0.3" }, "funding": { @@ -4274,28 +4296,25 @@ } }, "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", "devOptional": true, "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" - }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", "devOptional": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -4569,26 +4588,26 @@ } }, "node_modules/better-auth": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.5.6.tgz", - "integrity": "sha512-QSpJTqaT1XVfWRQe/fm3PgeuwOIlz1nWX/Dx7nsHStJ382bLzmDbQk2u7IT0IJ6wS5SRxfqEE1Ev9TXontgyAQ==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.14.tgz", + "integrity": "sha512-c0/DvTQGDpgfj1knekCpQrg6PSWGDtfAtP7Ou6FkAhoE3RNnnIxLB5qKj6tRg53a1xsq93G6T68cNxrUZ7ZVmw==", "license": "MIT", "dependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/drizzle-adapter": "1.5.6", - "@better-auth/kysely-adapter": "1.5.6", - "@better-auth/memory-adapter": "1.5.6", - "@better-auth/mongo-adapter": "1.5.6", - "@better-auth/prisma-adapter": "1.5.6", - "@better-auth/telemetry": "1.5.6", - "@better-auth/utils": "0.3.1", + "@better-auth/core": "1.6.14", + "@better-auth/drizzle-adapter": "1.6.14", + "@better-auth/kysely-adapter": "1.6.14", + "@better-auth/memory-adapter": "1.6.14", + "@better-auth/mongo-adapter": "1.6.14", + "@better-auth/prisma-adapter": "1.6.14", + "@better-auth/telemetry": "1.6.14", + "@better-auth/utils": "0.4.1", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", - "better-call": "1.3.2", + "better-call": "1.3.5", "defu": "^6.1.4", "jose": "^6.1.3", - "kysely": "^0.28.12", + "kysely": "^0.28.17 || ^0.29.0", "nanostores": "^1.1.1", "zod": "^4.3.6" }, @@ -4600,7 +4619,7 @@ "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", - "drizzle-orm": ">=0.41.0", + "drizzle-orm": "^0.45.2", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", @@ -4674,14 +4693,14 @@ } }, "node_modules/better-auth/node_modules/@better-auth/drizzle-adapter": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.5.6.tgz", - "integrity": "sha512-VfFFmaoFw3ug12SiSuIwzrMoHyIVmkMGWm9gZ4sXdYYVX4HboCL4m3fjzOhppcmK5OGatRuU+N1UX6wxCITcXw==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.14.tgz", + "integrity": "sha512-lYs1jDudriKYMXNcLFLAvEvOEKbeKBFdDciG4H8qZhV+3+yghGC3f/H5qtgTDc8mGBPV+2tEvVgYqReurOSmNw==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "1.5.6", - "@better-auth/utils": "^0.3.0", - "drizzle-orm": ">=0.41.0" + "@better-auth/core": "^1.6.14", + "@better-auth/utils": "0.4.1", + "drizzle-orm": "^0.45.2" }, "peerDependenciesMeta": { "drizzle-orm": { @@ -4690,12 +4709,12 @@ } }, "node_modules/better-call": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.2.tgz", - "integrity": "sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.5.tgz", + "integrity": "sha512-kOFJkBP7utAQLEYrobZm3vkTH8mXq5GNgvjc5/XEST1ilVHaxXUXfeDeFlqoETMtyqS4+3/h4ONX2i++ebZrvA==", "license": "MIT", "dependencies": { - "@better-auth/utils": "^0.3.1", + "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" @@ -4763,16 +4782,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -4855,18 +4864,11 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "devOptional": true, "license": "MIT", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, "engines": { "node": ">=18" } @@ -4888,16 +4890,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", - "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -5004,7 +4996,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cookie": { @@ -5314,16 +5306,6 @@ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5583,9 +5565,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "devOptional": true, "license": "MIT" }, @@ -7116,9 +7098,9 @@ } }, "node_modules/jose": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", - "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -7265,12 +7247,12 @@ } }, "node_modules/kysely": { - "version": "0.28.15", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.15.tgz", - "integrity": "sha512-r2clcf7HLWvDXaVUEvQymXJY4i3bSOIV3xsL/Upy3ZfSv5HeKsk9tsqbBptLvth5qHEIhxeHTA2jNLyQABkLBA==", + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.2.tgz", + "integrity": "sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==", "license": "MIT", "engines": { - "node": ">=20.0.0" + "node": ">=22.0.0" } }, "node_modules/leven": { @@ -7615,13 +7597,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "devOptional": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7837,9 +7812,9 @@ } }, "node_modules/nanostores": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.2.0.tgz", - "integrity": "sha512-F0wCzbsH80G7XXo0Jd9/AVQC7ouWY6idUCTnMwW5t/Rv9W8qmO6endavDwg7TNp5GbugwSukFMVZqzPSrSMndg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.3.0.tgz", + "integrity": "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==", "funding": [ { "type": "github", @@ -7916,6 +7891,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "devOptional": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8092,16 +8078,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -9043,9 +9019,9 @@ } }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "devOptional": true, "license": "MIT" }, @@ -9236,26 +9212,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", - "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "devOptional": true, - "license": "MIT" - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9398,11 +9354,14 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "devOptional": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { "version": "0.2.15", @@ -9421,30 +9380,10 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", - "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "devOptional": true, "license": "MIT", "engines": { @@ -9924,29 +9863,6 @@ } } }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/vite-plugin-pwa": { "version": "0.21.2", "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.21.2.tgz", @@ -9993,65 +9909,79 @@ } }, "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", "devOptional": true, "license": "MIT", "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, - "@types/debug": { + "@opentelemetry/api": { "optional": true }, "@types/node": { "optional": true }, - "@vitest/browser": { + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { "optional": true }, "@vitest/ui": { @@ -10062,33 +9992,9 @@ }, "jsdom": { "optional": true - } - } - }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "3.2.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true }, "vite": { - "optional": true + "optional": false } } }, @@ -10626,9 +10532,9 @@ } }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "devOptional": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index e946241..df41843 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "typescript-eslint": "^8.56.1", "vite": "^6.4.2", "vite-plugin-pwa": "^0.21.2", - "vitest": "^3.2.4" + "vitest": "^4.1.8" }, "overrides": { "@rollup/pluginutils": "5.3.0", From 01ed6dac003b1516b9ec08fc453c27d4b6fd14b8 Mon Sep 17 00:00:00 2001 From: Barcode Betty Date: Wed, 3 Jun 2026 15:52:52 +0000 Subject: [PATCH 4/9] fix(deps): pin safe versions of audit-flagged transitive deps (CAR-1162 audit) The CI's npm audit (10.8.2) flagged three transitive vulnerabilities that local newer-npm runs (11.x) miss due to advisory-DB divergence: - @babel/plugin-transform-modules-systemjs: 7.29.0 -> ^7.29.4 (CVE-2026-44728: arbitrary code generation, fixed in 7.29.4) - fast-uri: 3.1.0 -> ^3.1.2 (path traversal / host confusion via percent-encoded segments) - brace-expansion: 5.0.5 -> >=5.0.6 (DoS via large numeric range defeating max protection) These are non-breaking transitive updates within the same major version. The previous override for brace-expansion (>=1.1.13) was too loose to exclude 5.0.2-5.0.5; tightening it to >=5.0.6. Ref CAR-1162, CAR-1122, CAR-1078 Co-Authored-By: Paperclip --- package-lock.json | 138 +++++++++++++++++++++++----------------------- package.json | 6 +- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d83904..0464efb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,13 +85,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -141,14 +141,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -245,9 +245,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -269,29 +269,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -314,9 +314,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -374,9 +374,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -384,9 +384,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -433,13 +433,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1016,16 +1016,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.29.0" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1593,33 +1593,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -1627,14 +1627,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -4729,9 +4729,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -5925,9 +5925,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index df41843..52dadb0 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,10 @@ "@rollup/pluginutils": "5.3.0", "flatted": "^3.4.2", "serialize-javascript": "7.0.5", - "brace-expansion": ">=1.1.13", + "brace-expansion": ">=5.0.6", "lodash": ">=4.17.24", - "minimatch": "^10.2.4" + "minimatch": "^10.2.4", + "@babel/plugin-transform-modules-systemjs": "^7.29.4", + "fast-uri": "^3.1.2" } } From d92bcf433b0c570d9d600d41f21133b5e5665278 Mon Sep 17 00:00:00 2001 From: cs_carl Date: Wed, 3 Jun 2026 19:07:14 +0000 Subject: [PATCH 5/9] fix(ci): remove actions/setup-node from lint job to bypass corrupted runner cache Runner pod gitea-act-runner-cartsnitch-85b5984bb-527xw has a corrupt /root/.cache/act clone of actions/setup-node (missing dist/setup/index.js). SHA-pinning changed the cache hash but the fresh clone on that pod still ends up missing the dist directory. catthehacker/ubuntu:act-latest ships Node pre-installed; the lint job only needs ESLint + tsc, both of which are devDependencies installed by npm ci. Removing actions/setup-node from lint bypasses the corrupt pod cache entirely without affecting other jobs. Refs CAR-1162 Co-Authored-By: Paperclip --- .gitea/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 99b75fa..f4a417e 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -27,10 +27,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 - with: - node-version: "20" - cache: npm - run: npm ci - name: ESLint run: npx eslint . From 06162f9f15aba135275beac9d8a633cc70571a3c Mon Sep 17 00:00:00 2001 From: Barcode Betty Date: Wed, 3 Jun 2026 19:43:54 +0000 Subject: [PATCH 6/9] fix(ci): unblock dev build/deploy (CAR-1195) --- .gitea/workflows/ci.yml | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index f4a417e..a305abd 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -156,8 +156,8 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} target: prod - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=inline + cache-to: type=inline,mode=max - name: Scan frontend image for vulnerabilities uses: anchore/scan-action@v5 @@ -182,7 +182,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} target: prod - cache-from: type=gha + cache-from: type=inline - name: Create git tag if: github.event_name == 'push' && github.ref == 'refs/heads/main' @@ -248,8 +248,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=inline + cache-to: type=inline,mode=max - name: Scan receiptwitness image for vulnerabilities uses: anchore/scan-action@v5 @@ -276,7 +276,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha + cache-from: type=inline build-and-push-api: runs-on: ubuntu-latest @@ -336,8 +336,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=inline + cache-to: type=inline,mode=max - name: Scan api image for vulnerabilities uses: anchore/scan-action@v5 @@ -364,7 +364,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha + cache-from: type=inline build-and-push-auth: runs-on: ubuntu-latest @@ -424,8 +424,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=inline + cache-to: type=inline,mode=max - name: Scan auth image for vulnerabilities uses: anchore/scan-action@v5 @@ -452,7 +452,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | APT_CACHE_BUST=${{ github.run_id }} - cache-from: type=gha + cache-from: type=inline deploy-dev: runs-on: ubuntu-latest @@ -463,7 +463,7 @@ jobs: uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: repository: cartsnitch/infra - token: ${{ secrets.REGISTRY_TOKEN }} + token: ${{ secrets.CI_GITEA_TOKEN }} ref: main path: infra @@ -471,7 +471,16 @@ jobs: uses: azure/setup-kubectl@v4 - name: Install kustomize - uses: imranismail/setup-kustomize@v2 + # imranismail/setup-kustomize@v2 calls the Gitea API to record + # telemetry under the "kubernetes-sigs" user, which doesn't exist + # on this Gitea instance. Install the binary directly instead. + run: | + set -euo pipefail + version="5.4.3" + url="https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${version}/kustomize_v${version}_linux_amd64.tar.gz" + curl -fsSL --retry 3 "$url" | tar -xz -C /tmp kustomize + sudo install -m 0755 /tmp/kustomize /usr/local/bin/kustomize + kustomize version - name: Determine image tag for frontend id: frontend_tag @@ -553,7 +562,7 @@ jobs: uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: repository: cartsnitch/infra - token: ${{ secrets.REGISTRY_TOKEN }} + token: ${{ secrets.CI_GITEA_TOKEN }} ref: main path: infra @@ -561,7 +570,16 @@ jobs: uses: azure/setup-kubectl@v4 - name: Install kustomize - uses: imranismail/setup-kustomize@v2 + # imranismail/setup-kustomize@v2 calls the Gitea API to record + # telemetry under the "kubernetes-sigs" user, which doesn't exist + # on this Gitea instance. Install the binary directly instead. + run: | + set -euo pipefail + version="5.4.3" + url="https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${version}/kustomize_v${version}_linux_amd64.tar.gz" + curl -fsSL --retry 3 "$url" | tar -xz -C /tmp kustomize + sudo install -m 0755 /tmp/kustomize /usr/local/bin/kustomize + kustomize version - name: Determine image tag for frontend id: frontend_tag From 2573de86d56fd7f249fe90f75c4e7b8adcf3ec5e Mon Sep 17 00:00:00 2001 From: Barcode Betty <32+cs_betty@noreply.git.farh.net> Date: Wed, 3 Jun 2026 20:09:56 +0000 Subject: [PATCH 7/9] Update .gitea/workflows/ci.yml --- .gitea/workflows/ci.yml | 66 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index a305abd..673f0a4 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -542,16 +542,43 @@ jobs: cd infra/apps/overlays/dev kustomize edit set image ghcr.io/cartsnitch/auth=git.farh.net/cartsnitch/auth:${{ steps.auth_tag.outputs.tag }} - - name: Commit and push to infra + - name: Commit and push to infra (via PR) + env: + CI_GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }} run: | cd infra git config user.name "cartsnitch-ci[bot]" git config user.email "cartsnitch-ci[bot]@users.noreply.git.farh.net" git add apps/overlays/dev/kustomization.yaml git diff --cached --quiet && echo "No image changes to deploy" && exit 0 + BRANCH="ci/deploy-dev-${GITHUB_SHA}" + git checkout -b "$BRANCH" git commit -m "ci(dev): update cartsnitch, receiptwitness, api, and auth images" - git pull --rebase origin main - git push origin main + git push origin "$BRANCH" + PR_BODY=$(printf 'Auto-opened by deploy-dev (CAR-1195).\n\nBuild SHA: %s' "${GITHUB_SHA}") + PR_JSON=$(curl -sS -X POST \ + -H "Authorization: token ${CI_GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base main --arg title "ci(dev): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \ + "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls") + PR_NUM=$(echo "$PR_JSON" | jq -r '.number // empty') + if [ -z "$PR_NUM" ]; then + echo "::error::Failed to open PR against cartsnitch/infra: $PR_JSON" + exit 1 + fi + echo "Opened cartsnitch/infra PR #${PR_NUM} (head=${BRANCH})" + MERGE_RESP=$(curl -sS -X POST \ + -H "Authorization: token ${CI_GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"Do":"merge"}' \ + "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls/${PR_NUM}/merge") + MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') + if [ "$MERGED" != "true" ]; then + echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP" + echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge." + exit 1 + fi + echo "PR #${PR_NUM} merged into cartsnitch/infra main" deploy-uat: runs-on: ubuntu-latest @@ -641,13 +668,40 @@ jobs: cd infra/apps/overlays/uat kustomize edit set image ghcr.io/cartsnitch/auth=git.farh.net/cartsnitch/auth:${{ steps.auth_tag.outputs.tag }} - - name: Commit and push to infra + - name: Commit and push to infra (via PR) + env: + CI_GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }} run: | cd infra git config user.name "cartsnitch-ci[bot]" git config user.email "cartsnitch-ci[bot]@users.noreply.git.farh.net" git add apps/overlays/uat/kustomization.yaml git diff --cached --quiet && echo "No image changes to deploy" && exit 0 + BRANCH="ci/deploy-uat-${GITHUB_SHA}" + git checkout -b "$BRANCH" git commit -m "ci(uat): update cartsnitch, receiptwitness, api, and auth images" - git pull --rebase origin main - git push origin main + git push origin "$BRANCH" + PR_BODY=$(printf 'Auto-opened by deploy-uat (CAR-1195).\n\nBuild SHA: %s' "${GITHUB_SHA}") + PR_JSON=$(curl -sS -X POST \ + -H "Authorization: token ${CI_GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base main --arg title "ci(uat): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \ + "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls") + PR_NUM=$(echo "$PR_JSON" | jq -r '.number // empty') + if [ -z "$PR_NUM" ]; then + echo "::error::Failed to open PR against cartsnitch/infra: $PR_JSON" + exit 1 + fi + echo "Opened cartsnitch/infra PR #${PR_NUM} (head=${BRANCH})" + MERGE_RESP=$(curl -sS -X POST \ + -H "Authorization: token ${CI_GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"Do":"merge"}' \ + "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls/${PR_NUM}/merge") + MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') + if [ "$MERGED" != "true" ]; then + echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP" + echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge." + exit 1 + fi + echo "PR #${PR_NUM} merged into cartsnitch/infra main" From 3a69ec29b5e225288f17e8c431bfe7f71a55ec85 Mon Sep 17 00:00:00 2001 From: Barcode Betty <32+cs_betty@noreply.git.farh.net> Date: Wed, 3 Jun 2026 20:39:21 +0000 Subject: [PATCH 8/9] fix(ci): bind deploy PR API to secrets.CI_GITEA_TOKEN (CAR-1195) deploy-dev and deploy-uat had CI_GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }} which is the package-scoped container-registry token. PR creation and auto-merge against cartsnitch/infra would 403 on the first real push. Bind to secrets.CI_GITEA_TOKEN (the token the infra checkout already uses for branch push) so the Gitea API calls have repo-write scope. Co-Authored-By: Paperclip --- .gitea/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 673f0a4..662dc7b 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -544,7 +544,7 @@ jobs: - name: Commit and push to infra (via PR) env: - CI_GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }} run: | cd infra git config user.name "cartsnitch-ci[bot]" @@ -670,7 +670,7 @@ jobs: - name: Commit and push to infra (via PR) env: - CI_GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + CI_GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }} run: | cd infra git config user.name "cartsnitch-ci[bot]" From 83b553b58ec0ec5d5b0337c18ed0c27d2e0dddd8 Mon Sep 17 00:00:00 2001 From: Barcode Betty <32+cs_betty@noreply.git.farh.net> Date: Wed, 3 Jun 2026 20:53:54 +0000 Subject: [PATCH 9/9] ci: delete overlay deploy branches after merge Set delete_branch_after_merge:true on the auto-merge POST in both deploy-dev and deploy-uat so the per-deploy branches in cartsnitch/infra (ci/deploy-{dev,uat}-${GITHUB_SHA}) are removed once their overlay image-tag bump lands on main. Without this flag every successful deploy would leave a branch behind, accumulating in cartsnitch/infra and making future re-runs of the same SHA un-actionable from the existing branch name. Refs CAR-1195 (CTO fix #2). --- .gitea/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 662dc7b..27e95eb 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -570,7 +570,7 @@ jobs: MERGE_RESP=$(curl -sS -X POST \ -H "Authorization: token ${CI_GITEA_TOKEN}" \ -H "Content-Type: application/json" \ - -d '{"Do":"merge"}' \ + -d '{"Do":"merge","delete_branch_after_merge":true}' \ "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls/${PR_NUM}/merge") MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') if [ "$MERGED" != "true" ]; then @@ -696,7 +696,7 @@ jobs: MERGE_RESP=$(curl -sS -X POST \ -H "Authorization: token ${CI_GITEA_TOKEN}" \ -H "Content-Type: application/json" \ - -d '{"Do":"merge"}' \ + -d '{"Do":"merge","delete_branch_after_merge":true}' \ "https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls/${PR_NUM}/merge") MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') if [ "$MERGED" != "true" ]; then