Merge main into security/scanning-pipeline (bring up to date for merge)

This commit is contained in:
Jannis Braun
2026-07-13 11:20:45 +02:00
5 changed files with 63 additions and 15 deletions
+27 -7
View File
@@ -22,9 +22,14 @@ concurrency:
jobs: jobs:
build-and-test: build-and-test:
name: Build & test name: Build & test (Node ${{ matrix.node-version }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20, 24]
steps: steps:
- name: Harden the runner - name: Harden the runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
@@ -38,15 +43,10 @@ jobs:
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with: with:
version: 10.34.3 version: 10.34.3
# Node 20 is the project's supported runtime (package.json engines pins
# >=20 <21, .nvmrc says 20). Running the matrix on 20 also means the fresh
# install below pulls better-sqlite3's prebuilt binary for the correct ABI,
# which is what makes the server suite runnable in CI.
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with: with:
node-version: 20 node-version: ${{ matrix.node-version }}
cache: pnpm cache: pnpm
# The desktop postinstall tries to rebuild the native uiohook-napi module. # The desktop postinstall tries to rebuild the native uiohook-napi module.
@@ -70,3 +70,23 @@ jobs:
# Runs every package's `test` script (server, web, desktop) via vitest. # Runs every package's `test` script (server, web, desktop) via vitest.
- name: Test - name: Test
run: pnpm -r test run: pnpm -r test
# Aggregate gate reporting a single, matrix-independent "Build & test" status.
# Branch protection on main requires the "Build & test" context, but the matrix
# job above reports per-version contexts ("Build & test (Node 20/24)"). This job
# keeps the stable required context alive and fails unless every matrix leg
# succeeded (if: always() so a matrix failure still reports a definitive result
# instead of leaving the required check pending forever).
build-and-test-required:
name: Build & test
if: always()
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Verify matrix result
run: |
if [ "${{ needs.build-and-test.result }}" != "success" ]; then
echo "Matrix build-and-test did not succeed: ${{ needs.build-and-test.result }}"
exit 1
fi
echo "All matrix legs passed."
+20 -5
View File
@@ -465,10 +465,10 @@ briefly restarts the `backspace` container (clients reconnect automatically).
## Development ## Development
Requirements: **Node.js 20 (LTS)** and **pnpm 10**, both pinned (`.nvmrc` plus Requirements: **Node.js 20 or newer** and **pnpm 10**. The `.nvmrc` file keeps
the `packageManager` field), so `nvm use` and Corepack select the right versions Node 20 as the default development and production baseline; CI additionally
automatically. Newer Node majors are untested; the Docker image always builds on exercises Node 24, and newer majors generally work but are not part of the test
Node 20 regardless of your host. matrix. The Docker image continues to build on Node 20 regardless of your host.
```bash ```bash
pnpm install pnpm install
@@ -476,6 +476,21 @@ cp .env.example .env # set JWT_SECRET (openssl rand -hex 32)
pnpm dev # API server on :3005, Vite dev server on :5173 pnpm dev # API server on :3005, Vite dev server on :5173
``` ```
On Windows PowerShell, confirm Node 20 or newer and use the native copy command:
```powershell
node --version
pnpm install
Copy-Item .env.example .env
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```
Paste the generated value after `JWT_SECRET=` in `.env`, then start both
development servers with `pnpm dev`. Use `node --version` to confirm the active
version if pnpm reports an engine warning. This covers the server and web dev
servers; building the Electron desktop app still expects a POSIX shell (macOS or
Linux).
> **Server/web only?** `pnpm install` also builds the desktop app's native > **Server/web only?** `pnpm install` also builds the desktop app's native
> keyboard-hook module (`uiohook-napi`), which needs a C++ toolchain > keyboard-hook module (`uiohook-napi`), which needs a C++ toolchain
> (`make`, `g++`, `python3`). If those are missing it now **warns and continues**, > (`make`, `g++`, `python3`). If those are missing it now **warns and continues**,
@@ -604,7 +619,7 @@ packages/
| Layer | Technology | | Layer | Technology |
|--------------|------------| |--------------|------------|
| Server | Node.js 20 (LTS), Fastify 4, TypeScript (strict) | | Server | Node.js 20+, Fastify 4, TypeScript (strict) |
| Database | SQLite (better-sqlite3) + Drizzle ORM | | Database | SQLite (better-sqlite3) + Drizzle ORM |
| Auth | JWT + bcrypt | | Auth | JWT + bcrypt |
| Frontend | React 18, Vite 6, Tailwind CSS 3, Zustand 5 | | Frontend | React 18, Vite 6, Tailwind CSS 3, Zustand 5 |
+2 -2
View File
@@ -13,7 +13,7 @@
"scripts": { "scripts": {
"dev:server": "pnpm --filter @backspace/server dev", "dev:server": "pnpm --filter @backspace/server dev",
"dev:web": "pnpm --filter @backspace/web dev", "dev:web": "pnpm --filter @backspace/web dev",
"dev": "pnpm --filter @backspace/server dev & pnpm --filter @backspace/web dev", "dev": "pnpm --parallel --filter @backspace/server --filter @backspace/web dev",
"build:shared": "pnpm --filter @backspace/shared build", "build:shared": "pnpm --filter @backspace/shared build",
"build:server": "pnpm --filter @backspace/server build", "build:server": "pnpm --filter @backspace/server build",
"build:web": "pnpm --filter @backspace/web build", "build:web": "pnpm --filter @backspace/web build",
@@ -42,7 +42,7 @@
}, },
"packageManager": "pnpm@10.34.3", "packageManager": "pnpm@10.34.3",
"engines": { "engines": {
"node": ">=20.0.0 <21.0.0", "node": ">=20.0.0",
"pnpm": ">=10.0.0" "pnpm": ">=10.0.0"
} }
} }
+2 -1
View File
@@ -6,7 +6,7 @@
"author": "Jannis Braun", "author": "Jannis Braun",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=3005 tsx watch src/index.ts", "dev": "cross-env PORT=3005 tsx watch src/index.ts",
"start": "node --import tsx/esm src/index.ts", "start": "node --import tsx/esm src/index.ts",
"build": "tsc", "build": "tsc",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
@@ -41,6 +41,7 @@
"@types/jsonwebtoken": "^9.0.6", "@types/jsonwebtoken": "^9.0.6",
"@types/node": "^20.14.0", "@types/node": "^20.14.0",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"cross-env": "^7.0.3",
"drizzle-kit": "^0.24.0", "drizzle-kit": "^0.24.0",
"typescript": "^5.4.0", "typescript": "^5.4.0",
"vitest": "^4.0.18", "vitest": "^4.0.18",
+12
View File
@@ -120,6 +120,9 @@ importers:
'@types/ws': '@types/ws':
specifier: ^8.18.1 specifier: ^8.18.1
version: 8.18.1 version: 8.18.1
cross-env:
specifier: ^7.0.3
version: 7.0.3
drizzle-kit: drizzle-kit:
specifier: ^0.24.0 specifier: ^0.24.0
version: 0.24.2 version: 0.24.2
@@ -2656,6 +2659,11 @@ packages:
crc@3.8.0: crc@3.8.0:
resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==}
cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
hasBin: true
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -7993,6 +8001,10 @@ snapshots:
buffer: 5.7.1 buffer: 5.7.1
optional: true optional: true
cross-env@7.0.3:
dependencies:
cross-spawn: 7.0.6
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1