Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ jobs:
test-cp-integration:
name: Test (control-plane integration)
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 10
needs: [lint-typescript, typecheck-typescript]
steps:
- name: Checkout
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/deploy-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ jobs:
- name: Build Project
if: steps.check-secrets.outputs.configured == 'true'
run: vercel build --prod --token=${{ secrets.VERCEL_API_TOKEN }}
env:
# Required for NextAuth static generation - set via GitHub secret or Vercel will provide
NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL || 'https://localhost:3000' }}

- name: Deploy to Vercel
if: steps.check-secrets.outputs.configured == 'true'
Expand Down
7 changes: 3 additions & 4 deletions docs/GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ echo "repo_secrets_encryption_key: $(openssl rand -base64 32)"
# Modal API secret (use hex for this one)
echo "modal_api_secret: $(openssl rand -hex 32)"

# NextAuth secret
# Browser authentication secret (Terraform retains the legacy input name)
echo "nextauth_secret: $(openssl rand -base64 32)"

# GitHub webhook secret (only if enabling GitHub bot)
Expand Down Expand Up @@ -822,7 +822,7 @@ cloudflare_custom_domain = "app.example.com" # bare hostname, no scheme

Cloudflare provisions the DNS record and edge certificate automatically. Notes:

- The web app URL — including `NEXTAUTH_URL` and the links the bots send — becomes
- The canonical browser-auth origin and the links the bots send become
`https://{your-custom-domain}`, and the workers.dev route for the web Worker is disabled so the
app has a single canonical origin.
- Update the GitHub App callback URL (and the Google redirect URI, if Google login is enabled) to
Expand Down Expand Up @@ -918,7 +918,6 @@ Go to your fork's Settings → Secrets and variables → Actions, and add:
| `VERCEL_API_TOKEN` | Vercel API token _(only if `web_platform = "vercel"`)_ |
| `VERCEL_TEAM_ID` | Vercel team/account ID _(only if `web_platform = "vercel"`)_ |
| `VERCEL_PROJECT_ID` | Vercel project ID _(only if `web_platform = "vercel"`)_ |
| `NEXTAUTH_URL` | Your web app URL |
| `MODAL_TOKEN_ID` | Modal token ID |
| `MODAL_TOKEN_SECRET` | Modal token secret |
| `MODAL_WORKSPACE` | Modal workspace name |
Expand Down Expand Up @@ -955,7 +954,7 @@ Go to your fork's Settings → Secrets and variables → Actions, and add:
| `TOKEN_ENCRYPTION_KEY` | Generated encryption key (OAuth tokens) |
| `REPO_SECRETS_ENCRYPTION_KEY` | Generated encryption key (repo secrets) |
| `MODAL_API_SECRET` | Generated Modal API secret |
| `NEXTAUTH_SECRET` | Generated NextAuth secret |
| `NEXTAUTH_SECRET` | Generated browser-auth secret (legacy Actions secret name) |
| `ALLOWED_USERS` | Comma-separated GitHub usernames (or empty for all users) |
| `ALLOWED_EMAIL_DOMAINS` | Comma-separated email domains (or empty for all domains) |
| `ALLOWED_EMAILS` | Comma-separated exact email addresses (for individual users on shared domains) |
Expand Down
56 changes: 18 additions & 38 deletions docs/SETUP_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ What this does:

## Path A: Run the Web App Locally (Recommended Quick Start)

Use this when you already have a deployed control plane and sandbox backend, and only need local UI
development.
Use this with a dedicated development control plane whose `WEB_APP_URL` is `http://localhost:3000`.
Browser auth is origin-bound, so a production control plane configured for its deployed web origin
cannot authenticate a localhost web process.

### 1. Create local env file

Expand All @@ -74,23 +75,11 @@ cp packages/web/.env.example packages/web/.env.local
Edit `packages/web/.env.local`:

```bash
# GitHub App OAuth
GITHUB_CLIENT_ID=your_github_app_client_id
GITHUB_CLIENT_SECRET=your_github_app_client_secret

# Google OAuth (optional — enables "Sign in with Google"). Create a Web OAuth
# client at https://console.cloud.google.com/apis/credentials with redirect URI
# http://localhost:3000/api/auth/callback/google. Set NEXT_PUBLIC_GOOGLE_ENABLED=true
# to reveal the button (inlined at build time — restart the dev server after changing).
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Match the providers configured on the development control plane. This value
# is inlined at build time, so restart the dev server after changing it.
NEXT_PUBLIC_GOOGLE_ENABLED=

# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your_generated_secret

# Backend endpoints (deployed)
# Development control-plane endpoints
CONTROL_PLANE_URL=https://open-inspect-control-plane-<name>.<subdomain>.workers.dev
NEXT_PUBLIC_WS_URL=wss://open-inspect-control-plane-<name>.<subdomain>.workers.dev

Expand All @@ -99,17 +88,6 @@ NEXT_PUBLIC_WS_URL=wss://open-inspect-control-plane-<name>.<subdomain>.workers.d
# terraform state or the deployed web app's env).
SERVICE_AUTH_SECRET=your_web_service_secret

# Optional access control (a user is admitted if they match ANY allowlist)
ALLOWED_USERS=
ALLOWED_EMAIL_DOMAINS=
# Exact emails (any provider's verified email) — for users on shared domains
ALLOWED_EMAILS=
# GitHub orgs whose active members can sign in. Requests read:org only when set,
# then checks active org membership with the user's OAuth token. Requires GitHub
# App Organization permissions: Members read-only.
ALLOWED_GITHUB_ORGS=
UNSAFE_ALLOW_ALL_USERS=false

# Optional whitelabel branding (defaults shown). NEXT_PUBLIC_* vars are
# inlined into the client bundle at build time — restart `npm run dev`
# after changing them.
Expand All @@ -121,16 +99,18 @@ NEXT_PUBLIC_APP_ICON_URL=

Do not commit `packages/web/.env.local`.

Generate a secret value for `NEXTAUTH_SECRET` (never for `SERVICE_AUTH_SECRET`, which must be read
from the deployment as described above):

```bash
openssl rand -base64 32
```
OAuth provider credentials are not web environment variables. Better Auth runs in the control plane,
so configure `github_client_id` and `github_client_secret`—and, when enabled, `google_client_id` and
`google_client_secret`—on the development control plane through Terraform. See
[Create GitHub App](GETTING_STARTED.md#step-3-create-github-app) and
[Enable Google Login](GETTING_STARTED.md#enable-google-login-optional) for the complete provider
setup. `NEXT_PUBLIC_GOOGLE_ENABLED` only controls whether the web UI offers Google sign-in and must
match the providers configured on the control plane.

If you are using someone else's deployed backend, do not generate your own `SERVICE_AUTH_SECRET`.
Use the web service secret configured in that backend deployment (the control plane only accepts
signatures under its own copy).
signatures under its own copy). That backend must also be configured with
`WEB_APP_URL=http://localhost:3000`; otherwise use its deployed web app rather than a local UI.

### 3. Configure GitHub callback URL

Expand Down Expand Up @@ -235,9 +215,9 @@ Your GitHub callback URL does not exactly match the running app URL.

### Access denied after sign-in

Check `ALLOWED_USERS`, `ALLOWED_EMAIL_DOMAINS`, and `ALLOWED_GITHUB_ORGS` in
`packages/web/.env.local`. If `ALLOWED_GITHUB_ORGS` is set, make sure your GitHub App has
Organization permissions: Members read-only and that the updated permission was republished and
Check `allowed_users`, `allowed_email_domains`, `allowed_emails`, and `allowed_github_orgs` in the
control plane's Terraform configuration. If `allowed_github_orgs` is set, make sure your GitHub App
has Organization permissions: Members read-only and that the updated permission was republished and
approved for the installation.

### Web can load, but session APIs return 401
Expand Down
42 changes: 8 additions & 34 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,54 +113,28 @@ export default tseslint.config(
},
},

// Web BFF routes depend on the server-auth seam, not directly on the
// current authentication framework. The auth endpoints own the framework
// integration and are intentionally excluded.
// Web code depends on app-owned auth and request seams. OAuth and session
// protocol code is owned by the control plane.
{
files: [
"packages/web/src/app/api/**/*.{ts,tsx}",
"packages/web/src/lib/integration-settings-proxy.ts",
],
ignores: ["packages/web/src/app/api/auth/**"],
files: ["packages/web/src/**/*.{ts,tsx}"],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "next-auth",
message: "Use getServerAuthSession from @/lib/server-auth-session.",
message: "Use the app-owned browser authentication seams.",
},
],
patterns: [
{
regex: "(?:^|/)lib/auth$",
message: "Use getServerAuthSession from @/lib/server-auth-session.",
group: ["next-auth/*"],
message: "Use the app-owned browser authentication seams.",
},
],
},
],
},
},

// Web code depends on app-owned auth and request seams so the terminal
// browser-auth implementation can replace NextAuth and add its request
// contract without another consumer migration.
{
files: ["packages/web/src/**/*.{ts,tsx}"],
ignores: [
"packages/web/src/app/api/**",
"packages/web/src/lib/auth-session.tsx",
"packages/web/src/lib/auth-session.test.tsx",
],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "next-auth/react",
message: "Use the app-owned boundary from @/lib/auth-session.",
regex: "(?:^|/)lib/auth$",
message: "Use getServerAuthSession from @/lib/server-auth-session.",
},
],
},
Expand Down
Loading
Loading