mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
7d0e90eb47
The hook->permission map existed verbatim twice (the host supervisor and the plugin SDK) and the permission list four times (envelope, SDK manifest, and both admin panels in the client). All of them were in sync when measured - 63 entries each, 15 hook entries each - so this changes no behaviour. It removes a quiet outage: a hook whose permission is added on only one side fails silently in production, with the plugin installing, activating and then simply never being called. protocol/envelope.ts is the single source now. METHOD_PERMISSION was typed Record<KnownMethod, string>, so its value side was unconstrained - 'db:read:trps' compiled and made the method unreachable forever. It is `as const satisfies Record<KnownMethod, KnownPermission>` now, which catches a typo'd value, a missing key and an extra key. The derived KnownPermission and MethodPermission<M> are what the @PluginMethod decorator will check its argument against. Deliberately no explicit annotation on METHOD_PERMISSION: with one, typeof is that Record, MethodPermission<M> widens to the whole union, and the check silently evaporates. server/scripts/gen-plugin-facts.ts imports envelope.ts and writes the SDK and shared copies. It does not scrape. The guard it replaces pulled the block out of plugin-supervisor.ts with a regex that goes null on a reformat, and it ran only from prepublishOnly - drift would have surfaced as a broken npm release. The generated files are checked in because publish-plugin-sdk builds from a standalone checkout with no server present. The SDK's re-exported types stay wide. plugin-sdk compiles under strict, and grantGaps indexes HOOK_PERMISSION with a plain string, so an `as const` there is TS7053 and would break the publish. Strictness belongs on the host side. --check also fails on a permission with no admin.plugins.perm.* translation and on one the CLI has no hint for. Both are silent today. plugin-sdk/** was in no workflow path filter, so nothing in CI ever ran its tests. It is in the filter now, alongside a job that runs the drift check.
232 lines
6.4 KiB
YAML
232 lines
6.4 KiB
YAML
name: Tests
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main, dev]
|
|
paths:
|
|
- 'server/**'
|
|
- 'client/**'
|
|
- 'shared/**'
|
|
- 'nest-mcp/**'
|
|
- 'plugin-sdk/**'
|
|
- '.github/workflows/test.yml'
|
|
|
|
jobs:
|
|
plugin-facts:
|
|
name: Plugin Permission Facts
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: npm
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace server
|
|
|
|
# The plugin permission facts live once, in
|
|
# server/src/nest/plugins/protocol/envelope.ts. Every other copy - the SDK's
|
|
# generated/host-facts.ts and shared's plugin-permissions.ts - is generated from it
|
|
# and checked in, because publish-plugin-sdk builds from a standalone checkout with
|
|
# no server present. This fails the PR if a copy drifts, if a new permission has no
|
|
# admin.plugins.perm.* translation, or if the CLI has no hint for it.
|
|
- name: Check the generated plugin facts are in sync
|
|
run: cd server && npm run check:plugin-facts
|
|
|
|
i18n-parity:
|
|
name: i18n Key Parity
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
|
|
- name: Check i18n key parity
|
|
run: node shared/scripts/i18n-parity.mjs --strict
|
|
|
|
shared-contracts:
|
|
name: Shared Contracts (Zod)
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared
|
|
|
|
- name: Typecheck
|
|
run: cd shared && npm run typecheck
|
|
|
|
- name: Run tests
|
|
run: cd shared && npm test
|
|
|
|
nest-mcp-package:
|
|
name: nest-mcp Package
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace nest-mcp
|
|
|
|
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
|
# Same lockfile quirk as server-tests: the Linux native binary is
|
|
# omitted, and nest-mcp's vitest config uses the SWC transform too.
|
|
run: |
|
|
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
|
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
|
|
|
- name: Build
|
|
run: npm run build --workspace=nest-mcp
|
|
|
|
- name: Typecheck
|
|
run: cd nest-mcp && npm run typecheck
|
|
|
|
- name: Lint
|
|
run: cd nest-mcp && npm run lint:check
|
|
|
|
- name: Run tests
|
|
run: cd nest-mcp && npm test
|
|
|
|
server-tests:
|
|
name: Server Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
|
# The lockfile was generated on Windows and omits @swc/core's Linux
|
|
# optional native binary, so npm ci/install skips it on the runner.
|
|
# Install the matching version explicitly so the server's SWC transform
|
|
# (server/vitest.config.ts) can load.
|
|
run: |
|
|
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
|
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Build nest-mcp
|
|
# Server typecheck/build resolve @trek/nest-mcp's types from its dist
|
|
# (tests alias the package source, but tsc does not).
|
|
run: npm run build --workspace=nest-mcp
|
|
|
|
- name: Build server (tsc -> dist)
|
|
run: cd server && npm run build
|
|
|
|
- name: Smoke production require chain
|
|
# Vitest aliases @trek/nest-mcp to its source, so only this exercises
|
|
# what production runs: nest-mcp's built dist resolving the MCP SDK's
|
|
# subpath exports through the tsconfig-paths/register runtime hook.
|
|
run: cd server && node --require tsconfig-paths/register -e "require('@trek/nest-mcp')"
|
|
|
|
- name: Typecheck
|
|
run: cd server && npm run typecheck
|
|
|
|
- name: Lint
|
|
run: cd server && npm run lint:check
|
|
|
|
- name: Run tests
|
|
run: cd server && npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: backend-coverage
|
|
path: server/coverage/
|
|
retention-days: 7
|
|
|
|
client-quality:
|
|
# Split out of client-tests: the suite takes ~11 minutes, and having the
|
|
# gates in front of it meant a single lint finding threw away the whole test
|
|
# signal for that run. Both jobs pay the install/build, which is cheap next
|
|
# to running the two in series.
|
|
name: Client Types & Lint
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared && npm ci --workspace client
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Typecheck
|
|
run: cd client && npm run typecheck
|
|
|
|
- name: Lint
|
|
run: cd client && npm run lint:check
|
|
|
|
- name: Page pattern check
|
|
run: cd client && npm run lint:pages
|
|
|
|
client-tests:
|
|
name: Client Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared && npm ci --workspace client
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Run tests
|
|
run: cd client && npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: frontend-coverage
|
|
path: client/coverage/
|
|
retention-days: 7
|