From cae2458f0390884be21f6f7619c6fb5c65001cef Mon Sep 17 00:00:00 2001 From: tada5hi Date: Wed, 20 May 2026 14:47:51 +0200 Subject: [PATCH 1/6] ci: exercise migrations against MySQL and PostgreSQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing `test` job builds the schema via `dataSource.synchronize()` in `apps//test/app/database.ts`, so migration files in `apps//src/adapters/database/migrations/{mysql,postgres}/` are never exercised. SQL syntax errors and broken `down()` regressions only surface in production deployments. Add a `tests-migrations` job that runs the migration CLI end-to-end for server-core, server-storage, and server-telemetry against fresh MySQL 9 and Postgres 18 containers: `run` -> revert all in reverse order -> `run` (idempotency replay). Every `up()` / `down()` is exercised, not just the latest. A pre-flight step counts compiled migrations and fails loudly if zero — without this guard, typeorm silently reports "No migrations are pending" with exit 0 when the CLI runs from the wrong working directory, which is the same silent- pass failure mode this job exists to fix. Pin `docker-compose.yml` images to `mysql:9` and `postgres:18` to match the versions the existing test job uses, so local migration runs match CI. Refs authup/authup#3067, authup/authup#3068. --- .agents/testing.md | 26 +++++++++++++ .github/workflows/main.yml | 76 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 4 +- 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/.agents/testing.md b/.agents/testing.md index 12c425e3f..1176a9bd5 100644 --- a/.agents/testing.md +++ b/.agents/testing.md @@ -231,3 +231,29 @@ Existing fakes to reuse: - `FakeAnalysisMetadataRecalculator` / `FakeAnalysisNodeMetadataRecalculator` / `FakeAnalysisFileMetadataRecalculator` — record `recalc()` and `recalcDebounced()` calls When a dependency has no fake yet, create one in the entity's test directory (`test/unit/core/entities//`) implementing the port interface. + +## Migration Tests + +The `test` CI job runs the integration suite against MySQL, Postgres, and SQLite, but the schema is built via `dataSource.synchronize()` (see `apps//test/app/database.ts`) — migration files in `apps//src/adapters/database/migrations/{mysql,postgres}/` are **not** exercised by that suite. + +A separate `tests-migrations` CI job runs the migration CLI end-to-end for `server-core`, `server-storage`, and `server-telemetry` against a fresh MySQL and Postgres container: + +1. `migration run` — applies all migrations forward +2. `migration revert` × N — undoes every migration in reverse order (verifies every `down()` works) +3. `migration run` — re-applies the full chain (verifies idempotency) + +This catches SQL syntax errors, cross-DB type mismatches, and `down()` regressions across every migration. It does **not** catch data-correctness bugs in `UPDATE`/`INSERT` migrations against pre-existing rows — those still require manual smoke-testing against a populated database. + +The job pre-flights with a sanity check that the compiled migrations exist under `apps//dist/adapters/database/migrations/{mysql,postgres}/` — without this guard, running the CLI from the wrong working directory results in typeorm silently reporting "No migrations are pending" with exit code 0, masking the failure. + +Locally, run the same flow with a running compose stack: + +```bash +docker compose up -d mysql # or: postgres +cd apps/server-core # or: server-storage / server-telemetry + +DB_TYPE=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_USERNAME=root DB_PASSWORD=start123 DB_DATABASE=app \ + node dist/cli/index.mjs migration run +``` + +The CLI auto-creates the target database if it does not exist. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cb07f1548..6a2be1acf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -136,6 +136,82 @@ jobs: run: | npm run test + tests-migrations: + name: Test Migrations + needs: [build] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + service: [ server-core, server-storage, server-telemetry ] + db: [ mysql, postgres ] + include: + - db: mysql + port: 3306 + user: root + - db: postgres + port: 5432 + user: postgres + + env: + DB_TYPE: ${{ matrix.db }} + DB_HOST: 127.0.0.1 + DB_PORT: ${{ matrix.port }} + DB_USERNAME: ${{ matrix.user }} + DB_PASSWORD: start123 + DB_DATABASE: app + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install + uses: ./.github/actions/install + with: + node-version: ${{ env.NODE_VERSION }} + node-registry: ${{ env.NODE_REGISTRY }} + + - name: Build + uses: ./.github/actions/build + + - name: Verify compiled migrations exist + working-directory: apps/${{ matrix.service }} + run: | + count=$(ls dist/adapters/database/migrations/${{ matrix.db }}/*.mjs 2>/dev/null | wc -l | tr -d ' ') + if [ "$count" = "0" ]; then + echo "ERROR: no compiled migrations in apps/${{ matrix.service }}/dist/adapters/database/migrations/${{ matrix.db }}/" + exit 1 + fi + echo "Found $count migration(s)" + echo "MIGRATION_COUNT=$count" >> "$GITHUB_ENV" + + - name: Start ${{ matrix.db }} + run: docker compose up -d ${{ matrix.db }} + + - name: Wait for ${{ matrix.db }} to be ready + run: | + if [ "${{ matrix.db }}" = "mysql" ]; then + timeout 120 bash -c 'until docker compose exec -T mysql mysqladmin ping -h127.0.0.1 --silent; do sleep 2; done' + else + timeout 60 bash -c 'until docker compose exec -T postgres pg_isready -U postgres; do sleep 2; done' + fi + + - name: Run migrations forward + working-directory: apps/${{ matrix.service }} + run: node dist/cli/index.mjs migration run + + - name: Revert all migrations + working-directory: apps/${{ matrix.service }} + run: | + for ((i = 1; i <= MIGRATION_COUNT; i++)); do + node dist/cli/index.mjs migration revert + done + + - name: Re-apply all migrations (idempotency) + working-directory: apps/${{ matrix.service }} + run: node dist/cli/index.mjs migration run + lint: needs: [build] runs-on: ubuntu-latest diff --git a/docker-compose.yml b/docker-compose.yml index d5116d7c2..d2e1aff69 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.9' services: mysql: - image: mysql + image: mysql:9 restart: always healthcheck: test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] @@ -14,7 +14,7 @@ services: ports: - '3306:3306' postgres: - image: postgres + image: postgres:18 restart: always healthcheck: test: [ "CMD", "pg_isready" ] From 8d332d0c7d7c240fce0403a47d614ee4dabad605 Mon Sep 17 00:00:00 2001 From: tada5hi Date: Wed, 20 May 2026 15:16:21 +0200 Subject: [PATCH 2/6] ci(migrations): auth mysqladmin probe; document full local flow - mysqladmin ping now passes -uroot -pstart123 to avoid Access denied on MySQL 8+ images (matches the existing test job). - Expand the local repro in .agents/testing.md to show the full run -> revert xN -> run cycle and a Postgres env variant. --- .agents/testing.md | 26 ++++++++++++++++++++++---- .github/workflows/main.yml | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.agents/testing.md b/.agents/testing.md index 1176a9bd5..43fb8fa70 100644 --- a/.agents/testing.md +++ b/.agents/testing.md @@ -246,14 +246,32 @@ This catches SQL syntax errors, cross-DB type mismatches, and `down()` regressio The job pre-flights with a sanity check that the compiled migrations exist under `apps//dist/adapters/database/migrations/{mysql,postgres}/` — without this guard, running the CLI from the wrong working directory results in typeorm silently reporting "No migrations are pending" with exit code 0, masking the failure. -Locally, run the same flow with a running compose stack: +Locally, run the same `run → revert × N → run` flow against a running compose stack: ```bash -docker compose up -d mysql # or: postgres +# MySQL +docker compose up -d mysql cd apps/server-core # or: server-storage / server-telemetry -DB_TYPE=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_USERNAME=root DB_PASSWORD=start123 DB_DATABASE=app \ - node dist/cli/index.mjs migration run +export DB_TYPE=mysql DB_HOST=127.0.0.1 DB_PORT=3306 \ + DB_USERNAME=root DB_PASSWORD=start123 DB_DATABASE=app + +node dist/cli/index.mjs migration run +node dist/cli/index.mjs migration revert # repeat once per migration +node dist/cli/index.mjs migration run # idempotency replay +``` + +```bash +# Postgres +docker compose up -d postgres +cd apps/server-core + +export DB_TYPE=postgres DB_HOST=127.0.0.1 DB_PORT=5432 \ + DB_USERNAME=postgres DB_PASSWORD=start123 DB_DATABASE=app + +node dist/cli/index.mjs migration run +node dist/cli/index.mjs migration revert +node dist/cli/index.mjs migration run ``` The CLI auto-creates the target database if it does not exist. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a2be1acf..19d568158 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -192,7 +192,7 @@ jobs: - name: Wait for ${{ matrix.db }} to be ready run: | if [ "${{ matrix.db }}" = "mysql" ]; then - timeout 120 bash -c 'until docker compose exec -T mysql mysqladmin ping -h127.0.0.1 --silent; do sleep 2; done' + timeout 120 bash -c 'until docker compose exec -T mysql mysqladmin ping -h127.0.0.1 -uroot -pstart123 --silent; do sleep 2; done' else timeout 60 bash -c 'until docker compose exec -T postgres pg_isready -U postgres; do sleep 2; done' fi From 253b981c333e870f53e3bb851e5db62cca098ae1 Mon Sep 17 00:00:00 2001 From: tada5hi Date: Wed, 20 May 2026 16:14:23 +0200 Subject: [PATCH 3/6] build: regenerate package-lock.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release commit 14e5ccadd bumped apps/client-ui/package.json (and others) to use ^0.9.0 of @privateaim/kit / @privateaim/server-kit, but the package-lock.json node for apps/client-ui still recorded the previous ^0.8.31 constraints. As a result npm ci could not satisfy the lockfile and failed with 'Missing: @privateaim/kit@0.8.43 from lock file', breaking CI on master and every branch since the release. Regenerating the lockfile records the workspace 0.9.0 versions plus the 0.8.43 registry copies that server-storage-kit (^0.8.21) and server-test-kit (^0.8.37) still pull in — no package.json changes. --- package-lock.json | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/package-lock.json b/package-lock.json index 25e6f9ffb..9227675e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2414,6 +2414,16 @@ "integrity": "sha512-00+4zWS0df0RBHNuQUixzBhYLzyqSDvBr7VsQiReT0fv2r52/mqNHcPNp4cts6O/bDIvz5O6Zw0S4jlNug9Kkw==", "license": "MIT" }, + "node_modules/@ebec/http": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ebec/http/-/http-2.3.0.tgz", + "integrity": "sha512-7rPG7Bau1/reO/nQc+bpQABFvVj4+hFpARAgJcujrxGMuyq/ydN0+hjAJzxQDmwkfGY9GANfeCPUEwGuwmdjiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ebec": "^2.3.0" + } + }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -26353,6 +26363,52 @@ "@privateaim/storage-kit": "^0.8.21" } }, + "packages/server-storage-kit/node_modules/@privateaim/kit": { + "version": "0.8.43", + "resolved": "https://registry.npmjs.org/@privateaim/kit/-/kit-0.8.43.tgz", + "integrity": "sha512-uBSIKqHzvv2I0GHVDABi13htTOvUnU/GNNS288t+7Cvn89lFuGAEqJZaCiMpkA/Wi96necJB5F29EJosdXC9rw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ebec/http": "^2.3.0", + "nanoid": "^5.1.11", + "validup": "^0.2.2" + }, + "peerDependencies": { + "@authup/core-kit": "^1.0.0-beta.36", + "@authup/kit": "^1.0.0-beta.36" + } + }, + "packages/server-storage-kit/node_modules/@privateaim/server-kit": { + "version": "0.8.43", + "resolved": "https://registry.npmjs.org/@privateaim/server-kit/-/server-kit-0.8.43.tgz", + "integrity": "sha512-QXlZcoet/uCy2s199+2JI8VRtx1MX4RJjYuGKxu79K3aW9MUSbupY8EFy33l4dUtnTZ2Ew30Y194RHBq06r/4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ebec/http": "^2.3.0", + "@hapic/oauth2": "^3.2.0", + "@isaacs/ttlcache": "^2.1.4", + "@privateaim/kit": "^0.8.43", + "@socket.io/redis-emitter": "^5.1.0", + "eldin": "^1.1.0", + "envix": "^1.5.0", + "hapic": "^2.8.2", + "orkos": "^1.1.1", + "triple-beam": "^1.4.1", + "winston": "^3.19.0", + "winston-transport": "^4.9.0" + }, + "peerDependencies": { + "@authup/access": "^1.0.0-beta.36", + "@authup/core-http-kit": "^1.0.0-beta.36", + "@authup/core-kit": "^1.0.0-beta.36", + "amqp-extension": "^4.0.0", + "rapiq": "^0.9.0", + "redis-extension": "^2.0.4", + "typeorm-extension": "^3.7.4" + } + }, "packages/server-telemetry": { "name": "@privateaim/server-telemetry", "version": "0.9.0", @@ -26432,6 +26488,52 @@ "@privateaim/server-kit": "^0.8.37" } }, + "packages/server-test-kit/node_modules/@privateaim/kit": { + "version": "0.8.43", + "resolved": "https://registry.npmjs.org/@privateaim/kit/-/kit-0.8.43.tgz", + "integrity": "sha512-uBSIKqHzvv2I0GHVDABi13htTOvUnU/GNNS288t+7Cvn89lFuGAEqJZaCiMpkA/Wi96necJB5F29EJosdXC9rw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ebec/http": "^2.3.0", + "nanoid": "^5.1.11", + "validup": "^0.2.2" + }, + "peerDependencies": { + "@authup/core-kit": "^1.0.0-beta.36", + "@authup/kit": "^1.0.0-beta.36" + } + }, + "packages/server-test-kit/node_modules/@privateaim/server-kit": { + "version": "0.8.43", + "resolved": "https://registry.npmjs.org/@privateaim/server-kit/-/server-kit-0.8.43.tgz", + "integrity": "sha512-QXlZcoet/uCy2s199+2JI8VRtx1MX4RJjYuGKxu79K3aW9MUSbupY8EFy33l4dUtnTZ2Ew30Y194RHBq06r/4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ebec/http": "^2.3.0", + "@hapic/oauth2": "^3.2.0", + "@isaacs/ttlcache": "^2.1.4", + "@privateaim/kit": "^0.8.43", + "@socket.io/redis-emitter": "^5.1.0", + "eldin": "^1.1.0", + "envix": "^1.5.0", + "hapic": "^2.8.2", + "orkos": "^1.1.1", + "triple-beam": "^1.4.1", + "winston": "^3.19.0", + "winston-transport": "^4.9.0" + }, + "peerDependencies": { + "@authup/access": "^1.0.0-beta.36", + "@authup/core-http-kit": "^1.0.0-beta.36", + "@authup/core-kit": "^1.0.0-beta.36", + "amqp-extension": "^4.0.0", + "rapiq": "^0.9.0", + "redis-extension": "^2.0.4", + "typeorm-extension": "^3.7.4" + } + }, "packages/storage-kit": { "name": "@privateaim/storage-kit", "version": "0.8.44", From beddd8630d8d3a7a0c0789b05ba03b0f2255cedc Mon Sep 17 00:00:00 2001 From: tada5hi Date: Wed, 20 May 2026 16:42:37 +0200 Subject: [PATCH 4/6] fix(build): bump stale kit/server-kit refs to ^0.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit server-storage-kit and server-test-kit referenced @privateaim/kit / @privateaim/server-kit at ^0.8.21 / ^0.8.37, but the workspace versions are now 0.9.0. npm therefore pulled the registry copies of those packages into nested node_modules — and the published 0.8.43 tarballs do not contain the dist/ directory, so any consumer of server-storage-kit or server-test-kit failed at import time with: Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../server-storage-kit/node_modules/@privateaim/server-kit/dist/index.mjs' Bumping the constraints to ^0.9.0 makes npm use the local workspace package (which has dist/), eliminating the nested broken installs. Drops 102 lines of stale registry entries from package-lock.json that were added by the previous regenerate. --- package-lock.json | 114 ++--------------------- packages/server-storage-kit/package.json | 8 +- packages/server-test-kit/package.json | 4 +- 3 files changed, 12 insertions(+), 114 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9227675e1..66d44997f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2414,16 +2414,6 @@ "integrity": "sha512-00+4zWS0df0RBHNuQUixzBhYLzyqSDvBr7VsQiReT0fv2r52/mqNHcPNp4cts6O/bDIvz5O6Zw0S4jlNug9Kkw==", "license": "MIT" }, - "node_modules/@ebec/http": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ebec/http/-/http-2.3.0.tgz", - "integrity": "sha512-7rPG7Bau1/reO/nQc+bpQABFvVj4+hFpARAgJcujrxGMuyq/ydN0+hjAJzxQDmwkfGY9GANfeCPUEwGuwmdjiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ebec": "^2.3.0" - } - }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -26353,62 +26343,16 @@ "version": "0.8.21", "license": "Apache-2.0", "devDependencies": { - "@privateaim/kit": "^0.8.21", - "@privateaim/server-kit": "^0.8.21", + "@privateaim/kit": "^0.9.0", + "@privateaim/server-kit": "^0.9.0", "@privateaim/storage-kit": "^0.8.21" }, "peerDependencies": { - "@privateaim/kit": "^0.8.21", - "@privateaim/server-kit": "^0.8.21", + "@privateaim/kit": "^0.9.0", + "@privateaim/server-kit": "^0.9.0", "@privateaim/storage-kit": "^0.8.21" } }, - "packages/server-storage-kit/node_modules/@privateaim/kit": { - "version": "0.8.43", - "resolved": "https://registry.npmjs.org/@privateaim/kit/-/kit-0.8.43.tgz", - "integrity": "sha512-uBSIKqHzvv2I0GHVDABi13htTOvUnU/GNNS288t+7Cvn89lFuGAEqJZaCiMpkA/Wi96necJB5F29EJosdXC9rw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ebec/http": "^2.3.0", - "nanoid": "^5.1.11", - "validup": "^0.2.2" - }, - "peerDependencies": { - "@authup/core-kit": "^1.0.0-beta.36", - "@authup/kit": "^1.0.0-beta.36" - } - }, - "packages/server-storage-kit/node_modules/@privateaim/server-kit": { - "version": "0.8.43", - "resolved": "https://registry.npmjs.org/@privateaim/server-kit/-/server-kit-0.8.43.tgz", - "integrity": "sha512-QXlZcoet/uCy2s199+2JI8VRtx1MX4RJjYuGKxu79K3aW9MUSbupY8EFy33l4dUtnTZ2Ew30Y194RHBq06r/4g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ebec/http": "^2.3.0", - "@hapic/oauth2": "^3.2.0", - "@isaacs/ttlcache": "^2.1.4", - "@privateaim/kit": "^0.8.43", - "@socket.io/redis-emitter": "^5.1.0", - "eldin": "^1.1.0", - "envix": "^1.5.0", - "hapic": "^2.8.2", - "orkos": "^1.1.1", - "triple-beam": "^1.4.1", - "winston": "^3.19.0", - "winston-transport": "^4.9.0" - }, - "peerDependencies": { - "@authup/access": "^1.0.0-beta.36", - "@authup/core-http-kit": "^1.0.0-beta.36", - "@authup/core-kit": "^1.0.0-beta.36", - "amqp-extension": "^4.0.0", - "rapiq": "^0.9.0", - "redis-extension": "^2.0.4", - "typeorm-extension": "^3.7.4" - } - }, "packages/server-telemetry": { "name": "@privateaim/server-telemetry", "version": "0.9.0", @@ -26479,59 +26423,13 @@ "@authup/access": "^1.0.0-beta.36", "@authup/core-kit": "^1.0.0-beta.36", "@privateaim/errors": "^0.8.42", - "@privateaim/server-kit": "^0.8.37" + "@privateaim/server-kit": "^0.9.0" }, "peerDependencies": { "@authup/access": "^1.0.0-beta.36", "@authup/core-kit": "^1.0.0-beta.36", "@privateaim/errors": "^0.8.42", - "@privateaim/server-kit": "^0.8.37" - } - }, - "packages/server-test-kit/node_modules/@privateaim/kit": { - "version": "0.8.43", - "resolved": "https://registry.npmjs.org/@privateaim/kit/-/kit-0.8.43.tgz", - "integrity": "sha512-uBSIKqHzvv2I0GHVDABi13htTOvUnU/GNNS288t+7Cvn89lFuGAEqJZaCiMpkA/Wi96necJB5F29EJosdXC9rw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ebec/http": "^2.3.0", - "nanoid": "^5.1.11", - "validup": "^0.2.2" - }, - "peerDependencies": { - "@authup/core-kit": "^1.0.0-beta.36", - "@authup/kit": "^1.0.0-beta.36" - } - }, - "packages/server-test-kit/node_modules/@privateaim/server-kit": { - "version": "0.8.43", - "resolved": "https://registry.npmjs.org/@privateaim/server-kit/-/server-kit-0.8.43.tgz", - "integrity": "sha512-QXlZcoet/uCy2s199+2JI8VRtx1MX4RJjYuGKxu79K3aW9MUSbupY8EFy33l4dUtnTZ2Ew30Y194RHBq06r/4g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ebec/http": "^2.3.0", - "@hapic/oauth2": "^3.2.0", - "@isaacs/ttlcache": "^2.1.4", - "@privateaim/kit": "^0.8.43", - "@socket.io/redis-emitter": "^5.1.0", - "eldin": "^1.1.0", - "envix": "^1.5.0", - "hapic": "^2.8.2", - "orkos": "^1.1.1", - "triple-beam": "^1.4.1", - "winston": "^3.19.0", - "winston-transport": "^4.9.0" - }, - "peerDependencies": { - "@authup/access": "^1.0.0-beta.36", - "@authup/core-http-kit": "^1.0.0-beta.36", - "@authup/core-kit": "^1.0.0-beta.36", - "amqp-extension": "^4.0.0", - "rapiq": "^0.9.0", - "redis-extension": "^2.0.4", - "typeorm-extension": "^3.7.4" + "@privateaim/server-kit": "^0.9.0" } }, "packages/storage-kit": { diff --git a/packages/server-storage-kit/package.json b/packages/server-storage-kit/package.json index 2f2347413..4491d4edd 100644 --- a/packages/server-storage-kit/package.json +++ b/packages/server-storage-kit/package.json @@ -19,13 +19,13 @@ "license": "Apache-2.0", "description": "This package contains server side db helpers & utilities.", "devDependencies": { - "@privateaim/kit": "^0.8.21", - "@privateaim/server-kit": "^0.8.21", + "@privateaim/kit": "^0.9.0", + "@privateaim/server-kit": "^0.9.0", "@privateaim/storage-kit": "^0.8.21" }, "peerDependencies": { - "@privateaim/kit": "^0.8.21", - "@privateaim/server-kit": "^0.8.21", + "@privateaim/kit": "^0.9.0", + "@privateaim/server-kit": "^0.9.0", "@privateaim/storage-kit": "^0.8.21" }, "scripts": { diff --git a/packages/server-test-kit/package.json b/packages/server-test-kit/package.json index b1a1440eb..c2f3e01dd 100644 --- a/packages/server-test-kit/package.json +++ b/packages/server-test-kit/package.json @@ -22,13 +22,13 @@ "@authup/access": "^1.0.0-beta.36", "@authup/core-kit": "^1.0.0-beta.36", "@privateaim/errors": "^0.8.42", - "@privateaim/server-kit": "^0.8.37" + "@privateaim/server-kit": "^0.9.0" }, "peerDependencies": { "@authup/access": "^1.0.0-beta.36", "@authup/core-kit": "^1.0.0-beta.36", "@privateaim/errors": "^0.8.42", - "@privateaim/server-kit": "^0.8.37" + "@privateaim/server-kit": "^0.9.0" }, "scripts": { "build": "rimraf ./dist && tsdown" From 3d1c593d4d9993b16c86881ba736c67802e09cec Mon Sep 17 00:00:00 2001 From: tada5hi Date: Thu, 21 May 2026 09:57:35 +0200 Subject: [PATCH 5/6] ci(migrations): pipefail-safe count and unauthed-warning-free mysqladmin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors authup/authup@cb89ead85: - Migration count step now uses 'shopt -s nullglob' + bash array glob instead of 'ls | wc -l'. Under set -e -o pipefail (GHA default) the pipe form can fail when the directory does not exist — which is precisely the case this step is designed to detect. - mysqladmin readiness probe now passes the password via the MYSQL_PWD environment variable rather than -p on the command line, eliminating the 'Using a password on the command line interface can be insecure' warning. --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 19d568158..94f98303a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -178,7 +178,9 @@ jobs: - name: Verify compiled migrations exist working-directory: apps/${{ matrix.service }} run: | - count=$(ls dist/adapters/database/migrations/${{ matrix.db }}/*.mjs 2>/dev/null | wc -l | tr -d ' ') + shopt -s nullglob + files=(dist/adapters/database/migrations/${{ matrix.db }}/*.mjs) + count=${#files[@]} if [ "$count" = "0" ]; then echo "ERROR: no compiled migrations in apps/${{ matrix.service }}/dist/adapters/database/migrations/${{ matrix.db }}/" exit 1 @@ -192,7 +194,7 @@ jobs: - name: Wait for ${{ matrix.db }} to be ready run: | if [ "${{ matrix.db }}" = "mysql" ]; then - timeout 120 bash -c 'until docker compose exec -T mysql mysqladmin ping -h127.0.0.1 -uroot -pstart123 --silent; do sleep 2; done' + timeout 120 bash -c 'until docker compose exec -T -e MYSQL_PWD="$DB_PASSWORD" mysql mysqladmin ping -h127.0.0.1 -uroot --silent; do sleep 2; done' else timeout 60 bash -c 'until docker compose exec -T postgres pg_isready -U postgres; do sleep 2; done' fi From 280676029b0db44e822792e82f6cf866495aa35a Mon Sep 17 00:00:00 2001 From: tada5hi Date: Thu, 21 May 2026 10:02:12 +0200 Subject: [PATCH 6/6] ci(migrations): use GHA services: blocks instead of docker compose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns the migration job with the existing test job in this workflow, which already uses GHA services: for mysql:9 / postgres:18. Removes the separate 'Start mysql/postgres' and 'Wait for ... ready' steps — GHA manages container lifecycle and health-check polling. The docker-compose.yml still exists for local development; only the CI job switches off it. docs say to run 'docker compose up' locally; that remains accurate. --- .github/workflows/main.yml | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 94f98303a..fc5789fd9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -162,6 +162,31 @@ jobs: DB_PASSWORD: start123 DB_DATABASE: app + services: + mysql: + image: mysql:9 + env: + MYSQL_ROOT_PASSWORD: start123 + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping -h localhost -pstart123" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + + postgres: + image: postgres:18 + env: + POSTGRES_PASSWORD: start123 + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U postgres" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + steps: - name: Checkout uses: actions/checkout@v6 @@ -188,17 +213,6 @@ jobs: echo "Found $count migration(s)" echo "MIGRATION_COUNT=$count" >> "$GITHUB_ENV" - - name: Start ${{ matrix.db }} - run: docker compose up -d ${{ matrix.db }} - - - name: Wait for ${{ matrix.db }} to be ready - run: | - if [ "${{ matrix.db }}" = "mysql" ]; then - timeout 120 bash -c 'until docker compose exec -T -e MYSQL_PWD="$DB_PASSWORD" mysql mysqladmin ping -h127.0.0.1 -uroot --silent; do sleep 2; done' - else - timeout 60 bash -c 'until docker compose exec -T postgres pg_isready -U postgres; do sleep 2; done' - fi - - name: Run migrations forward working-directory: apps/${{ matrix.service }} run: node dist/cli/index.mjs migration run