Skip to content

Commit 37af2eb

Browse files
committed
test(oauth): check OAuth scopes against a live server
Add `pnpm test:scopes`, which signs in through the extension's OAuth flow against a throwaway deployment (test/scopes/compose.yaml) and runs a probe for every Coder API method and CLI request the extension makes with the granted token. It also checks that each requested scope is needed by a named probe, and asserts the exact error of known gaps. `scopeProbes.test.ts` runs on every PR and uses the TypeScript checker to find every CoderApi method src/ references, failing when one has no probe. The workflow runs the suite on relevant changes against a pinned coder-preview image, and nightly against `latest`. `pnpm test` and the CI unit job leave it out.
1 parent c9eff9e commit 37af2eb

12 files changed

Lines changed: 1159 additions & 12 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: OAuth Scopes
2+
3+
# Pushes and PRs use the image pinned in compose.yaml; nightly runs use latest
4+
# to catch server changes early.
5+
on:
6+
push:
7+
branches: [main]
8+
# Code the probes run or import
9+
paths: &paths
10+
- src/**
11+
- test/mocks/**
12+
- test/scopes/**
13+
- package.json
14+
- pnpm-lock.yaml
15+
- vitest.config.mts
16+
- .github/workflows/oauth-scopes.yaml
17+
pull_request:
18+
paths: *paths
19+
schedule:
20+
- cron: "0 6 * * *"
21+
workflow_dispatch:
22+
23+
permissions:
24+
contents: read
25+
26+
jobs:
27+
live-server:
28+
name: Live Server Test (coder-preview)
29+
runs-on: ubuntu-24.04
30+
timeout-minutes: 15
31+
steps:
32+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33+
with:
34+
persist-credentials: false
35+
- uses: ./.github/actions/setup
36+
- run: docker compose -f test/scopes/compose.yaml up -d --wait
37+
env:
38+
CODER_IMAGE: ${{ github.event_name == 'schedule' && 'ghcr.io/coder/coder-preview:latest' || '' }}
39+
- run: pnpm test:scopes
40+
env:
41+
CODER_SCOPES_TEST_URL: http://localhost:7080

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ test/
9595
├── unit/ # Extension unit tests (mirrors src/ structure)
9696
├── webview/ # Webview unit tests (by package name)
9797
├── integration/ # VS Code integration tests (uses Mocha, not Vitest)
98+
├── scopes/ # OAuth scopes against a live server (`pnpm test:scopes`)
9899
├── utils/ # Test utilities that are also tested
99100
└── mocks/ # Shared test mocks
100101
```

‎CONTRIBUTING.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,22 @@ pnpm test:integration
242242
- Requires closing VS Code or running in a clean environment
243243
- Test files in `test/integration/` are compiled to `out/` before running
244244

245+
### OAuth Scope Tests
246+
247+
`test/scopes/` signs in through the extension's OAuth flow against a live
248+
server and runs the probes in `test/scopes/probes.ts` with the token. It needs
249+
Docker and a fresh deployment, since it creates users and workspaces, and
250+
`pnpm test` leaves it out:
251+
252+
```bash
253+
docker compose -f test/scopes/compose.yaml up -d --wait
254+
CODER_SCOPES_TEST_URL=http://localhost:7080 pnpm test:scopes
255+
docker compose -f test/scopes/compose.yaml down -v # before the next run
256+
```
257+
258+
Pull requests run against the coder-preview image pinned in `compose.yaml`;
259+
the nightly run uses `latest`. Set `CODER_IMAGE` to test another image.
260+
245261
## Development
246262

247263
> [!IMPORTANT]

‎package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
"storybook:build": "storybook build --config-dir .storybook",
3535
"storybook:ci": "storybook build --test --config-dir .storybook",
3636
"sync:vscode-themes": "node .storybook/themes/sync.mjs",
37-
"test": "cross-env CI=true ELECTRON_RUN_AS_NODE=1 electron node_modules/vitest/vitest.mjs",
37+
"test": "cross-env CI=true ELECTRON_RUN_AS_NODE=1 electron node_modules/vitest/vitest.mjs --project !scopes",
3838
"test:extension": "cross-env ELECTRON_RUN_AS_NODE=1 electron node_modules/vitest/vitest.mjs --project extension",
3939
"test:integration": "pnpm build:test && node esbuild.mjs && vscode-test",
40+
"test:scopes": "cross-env ELECTRON_RUN_AS_NODE=1 electron node_modules/vitest/vitest.mjs --project scopes",
4041
"test:webview": "cross-env ELECTRON_RUN_AS_NODE=1 electron node_modules/vitest/vitest.mjs --project webview",
4142
"typecheck": "concurrently -g -n extension,tests,packages,storybook \"tsc --noEmit\" \"tsc --noEmit -p test\" \"pnpm typecheck:packages\" \"tsc --noEmit -p .storybook\"",
4243
"typecheck:packages": "pnpm -r --filter \"./packages/*\" --parallel typecheck",

‎pnpm-workspace.yaml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ catalog:
2222
react-dom: ^19.3.0
2323
storybook: ^10.6.1
2424
storybook-addon-pseudo-states: ^10.6.1
25-
# typescript stays on the 6.0 API for typescript-eslint; TypeScript 7 runs `tsc`.
25+
# typescript stays on the 6.0 API for typescript-eslint and the compiler API in
26+
# test/unit/oauth/scopeProbes.test.ts; TypeScript 7 runs `tsc`.
2627
# https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/
2728
typescript: npm:@typescript/typescript6@^6.0.2
2829
vite: ^8.3.2

‎scripts/test-electron.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ pnpm --dir "$RUNNER_DIR" add "electron@$ELECTRON_VERSION"
3030

3131
echo "Running tests with Electron $ELECTRON_VERSION..."
3232
ELECTRON_RUN_AS_NODE=1 \
33-
"$RUNNER_DIR/node_modules/.bin/electron" node_modules/vitest/vitest.mjs
33+
"$RUNNER_DIR/node_modules/.bin/electron" node_modules/vitest/vitest.mjs --project "!scopes"

‎test/scopes/compose.yaml‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# A throwaway deployment for `pnpm test:scopes`; see CONTRIBUTING.md.
2+
services:
3+
postgres:
4+
image: postgres:17
5+
environment:
6+
POSTGRES_USER: coder
7+
POSTGRES_PASSWORD: coder
8+
POSTGRES_DB: coder
9+
healthcheck:
10+
test: pg_isready -U coder
11+
interval: 2s
12+
retries: 30
13+
14+
coder:
15+
image: ${CODER_IMAGE:-ghcr.io/coder/coder-preview@sha256:22951b2840d24d0b2dcb75990f499cb844840ecd763731cc0361683c1ee457aa}
16+
ports: ["127.0.0.1:7080:7080"]
17+
environment:
18+
CODER_PG_CONNECTION_URL: postgres://coder:coder@postgres:5432/coder?sslmode=disable
19+
CODER_HTTP_ADDRESS: 0.0.0.0:7080
20+
CODER_ACCESS_URL: http://localhost:7080
21+
CODER_OAUTH2_PROVIDER_ENABLE: "true"
22+
depends_on:
23+
postgres:
24+
condition: service_healthy
25+
healthcheck:
26+
test: curl -fs http://localhost:7080/healthz
27+
interval: 2s
28+
retries: 60

0 commit comments

Comments
 (0)