Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
04130c0
feat: local dev without third-party credentials
Kitenite May 16, 2026
2b609b5
feat: deployment profiles — OSS lenient, internal-dev/cloud strict
Kitenite May 16, 2026
f3c76b9
refactor: flip profile discriminator — strict by default, SUPERSET_OS…
Kitenite May 16, 2026
101cd30
fix: add ci profile so GitHub Actions builds don't trip strict valida…
Kitenite May 16, 2026
513d198
fix: address review findings on PR #4616
Kitenite May 16, 2026
f3254ef
fix: address CI build failure + remaining hardcoded prod URL defaults
Kitenite May 16, 2026
7be895d
docs: comprehensive design record for OSS local setup PR
Kitenite May 17, 2026
ee4848e
refactor local contributor profile
Kitenite May 17, 2026
46b9d83
chore: add local setup script
Kitenite May 17, 2026
8cf0e70
docs: clarify local env example
Kitenite May 17, 2026
05ccc7e
fix: tighten local profile guardrails
Kitenite May 17, 2026
716e682
fix: isolate local setup per worktree
Kitenite May 18, 2026
47ebfeb
fix: add local desktop sign-in form
Kitenite May 18, 2026
18c7cef
fix: keep local desktop sign-in bearer-only
Kitenite May 18, 2026
c6b8e87
Merge remote-tracking branch 'origin/main' into local-setup-no-env
Kitenite May 19, 2026
b716443
feat(web): one-click dev sign-in button for local development (#4778)
justincrich May 20, 2026
fd9f0a7
Merge remote-tracking branch 'origin/main' into local-setup-no-env
Kitenite May 20, 2026
149e343
Merge remote-tracking branch 'origin/local-setup-no-env' into local-s…
Kitenite May 20, 2026
71b11cd
Fix task sync test mock
Kitenite May 20, 2026
6264ced
Fix canary app metadata
Kitenite May 20, 2026
3391f45
Remove stale host service discovery call
Kitenite May 20, 2026
ed46380
Allow unsigned canary desktop builds
Kitenite May 20, 2026
57b0b78
Fix renderer env empty profile handling
Kitenite May 20, 2026
4c1b0e2
Constrain local dev profile behavior
Kitenite May 21, 2026
d69de5d
Keep unsigned canary builds out of update feed
Kitenite May 21, 2026
ea5e625
Merge remote-tracking branch 'origin/main' into local-setup-no-env
Kitenite May 21, 2026
ebe6f63
Preserve canary desktop user data path
Kitenite May 21, 2026
d41a728
Trim redundant canary release metadata
Kitenite May 21, 2026
32035f6
Clean up local dev notes and boot logging
Kitenite May 21, 2026
2b6ff9e
Trim unrelated Linear callback changes
Kitenite May 21, 2026
380b5d7
Remove nonessential local dev leftovers
Kitenite May 21, 2026
c68ce81
SUPER-771: Loud failures for automation runs (#4817)
justincrich Jul 4, 2026
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
72 changes: 54 additions & 18 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,38 +1,73 @@


# =============================================================================
# ROOT SUPERSET ENV
# Shared by all worktrees via direnv
# SUPERSET LOCAL DEVELOPMENT ENV
# Copied to .env by `bun setup:local`.
#
# Keep .env machine-local and untracked. Blank optional integration keys are
# intentional in the local profile; the app should boot without third-party
# credentials and degrade only when those specific features are exercised.
# =============================================================================

# -----------------------------------------------------------------------------
# Neon Organization Credentials
# Local Contributor Profile
# -----------------------------------------------------------------------------
NEON_ORG_ID=
NEON_PROJECT_ID=
NEON_API_KEY=
# Required for fresh-clone local development without third-party credentials.
SUPERSET_PROFILE=local

# Keep desktop dev state separate from production / canary installs.
# `bun setup:local` rewrites this to local-dev-<worktree>.
SUPERSET_WORKSPACE_NAME=local-dev

# -----------------------------------------------------------------------------
# Local Database
# -----------------------------------------------------------------------------
# `bun setup:local` rewrites these to a database name derived from the
# worktree path, so multiple local worktrees can share one Postgres container
# without sharing schema/auth state.
SUPERSET_LOCAL_DATABASE_NAME=superset
DATABASE_URL=postgres://superset:superset@localhost:5433/superset
DATABASE_URL_UNPOOLED=postgres://superset:superset@localhost:5433/superset

# -----------------------------------------------------------------------------
# Neon Database Credentials (Production)
# Local Ports
# -----------------------------------------------------------------------------
DATABASE_URL=
DATABASE_URL_UNPOOLED=
WEB_PORT=4640
API_PORT=4641
DESKTOP_VITE_PORT=4645
DESKTOP_NOTIFICATIONS_PORT=4646
ELECTRIC_PORT=4649
CADDY_ELECTRIC_PORT=4650
WRANGLER_PORT=4652

# -----------------------------------------------------------------------------
# Cross-App URLs (Local Dev)
# Local App URLs
# -----------------------------------------------------------------------------
NEXT_PUBLIC_API_URL=http://localhost:3001
NEXT_PUBLIC_WEB_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:4641
NEXT_PUBLIC_WEB_URL=http://localhost:4640
NEXT_PUBLIC_ADMIN_URL=http://localhost:3003
NEXT_PUBLIC_MARKETING_URL=http://localhost:3002
NEXT_PUBLIC_DOCS_URL=http://localhost:3004
NEXT_PUBLIC_ELECTRIC_URL=https://localhost:4650

# -----------------------------------------------------------------------------
# Better Auth
# Local Auth Defaults
# -----------------------------------------------------------------------------
BETTER_AUTH_SECRET=
BETTER_AUTH_SECRET=local_dev_secret_not_for_production
NEXT_PUBLIC_COOKIE_DOMAIN=localhost

# =============================================================================
# OPTIONAL INTEGRATION CREDENTIALS
# Leave these blank for the default local contributor flow.
# =============================================================================

# -----------------------------------------------------------------------------
# Neon Organization Credentials
# -----------------------------------------------------------------------------
# Only needed for Neon-backed/internal workflows. The local setup script uses the
# Docker Postgres URLs above.
NEON_ORG_ID=
NEON_PROJECT_ID=
NEON_API_KEY=

# -----------------------------------------------------------------------------
# OAuth Credentials (for Desktop App direct auth)
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +134,7 @@ KV_REST_API_TOKEN=

# QStash API token (used for background job scheduling in packages/trpc and apps/api)
QSTASH_TOKEN=
QSTASH_URL=

# QStash webhook signature verification keys (used to verify webhook requests)
QSTASH_CURRENT_SIGNING_KEY=
Expand All @@ -110,5 +146,5 @@ SUPERSET_MCP_API_KEY=
# Relay service URL (the v2 tunnel proxy that forwards cloud API calls
# to host-service instances on user devices). Local dev: http://localhost:4734
RELAY_URL=
# Browser-exposed relay URL — the web app's host-service tRPC + terminal WS.
NEXT_PUBLIC_RELAY_URL=
# Browser-exposed relay URL for the web app's host-service tRPC + terminal WS.
NEXT_PUBLIC_RELAY_URL=http://localhost:4734
17 changes: 12 additions & 5 deletions .github/workflows/build-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ on:
required: false
type: number
default: 30
skip_signing:
description: "Build macOS artifacts without code signing or notarization"
required: false
type: boolean
default: false

jobs:
build-macos:
Expand Down Expand Up @@ -112,11 +117,13 @@ jobs:
- name: Build Electron app
working-directory: apps/desktop
env:
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ inputs.skip_signing == false && secrets.MAC_CERTIFICATE || '' }}
CSC_KEY_PASSWORD: ${{ inputs.skip_signing == false && secrets.MAC_CERTIFICATE_PASSWORD || '' }}
APPLE_ID: ${{ inputs.skip_signing == false && secrets.APPLE_ID || '' }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ inputs.skip_signing == false && secrets.APPLE_ID_PASSWORD || '' }}
APPLE_TEAM_ID: ${{ inputs.skip_signing == false && secrets.APPLE_TEAM_ID || '' }}
CSC_IDENTITY_AUTO_DISCOVERY: ${{ inputs.skip_signing && 'false' || '' }}
SKIP_CODE_SIGNING: ${{ inputs.skip_signing && 'true' || 'false' }}
TARGET_ARCH: ${{ matrix.arch }}
run: bun run package -- --publish never --config ${{ inputs.electron_builder_config }} --${{ matrix.arch }}

Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/release-desktop-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ on:
required: false
type: boolean
default: false
skip_signing:
description: "Build unsigned macOS artifacts for manual testing only; does not update the canary release feed"
required: false
type: boolean
default: false

permissions:
contents: write
Expand Down Expand Up @@ -77,12 +82,13 @@ jobs:
electron_builder_config: electron-builder.canary.ts
artifact_prefix: desktop-canary
artifact_retention_days: 7
skip_signing: ${{ github.event.inputs.skip_signing == 'true' }}
secrets: inherit

release:
name: Update Canary Release
needs: [check-changes, build]
if: needs.check-changes.outputs.should_build == 'true'
if: needs.check-changes.outputs.should_build == 'true' && github.event.inputs.skip_signing != 'true'
runs-on: ubuntu-latest

steps:
Expand Down
6 changes: 3 additions & 3 deletions Caddyfile.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# Avoids browser's 6-connection limit when using 10+ Electric streams.
#
# Copy to Caddyfile: cp Caddyfile.example Caddyfile
# Install caddy: brew install caddy (macOS) / see https://caddyserver.com/docs/install
# Install caddy: brew install caddy

{
auto_https disable_redirects
}

https://localhost:3010 {
reverse_proxy localhost:3001 {
https://localhost:{$CADDY_ELECTRIC_PORT} {
reverse_proxy localhost:{$WRANGLER_PORT} {
flush_interval -1
}
}
46 changes: 8 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ If it runs in a terminal, it runs on Superset

| Requirement | Details |
|:------------|:--------|
| **OS** | macOS (Windows/Linux untested) |
| **OS** | macOS |
| **Runtime** | [Bun](https://bun.sh/) v1.0+ |
| **Version Control** | Git 2.20+ |
| **GitHub CLI** | [gh](https://cli.github.com/) |
Expand All @@ -85,57 +85,27 @@ If it runs in a terminal, it runs on Superset

### Build from Source

<details>
<summary>Click to expand build instructions</summary>
For a complete contributor workflow that boots a fresh clone with no third-party credentials (Neon / OAuth / Stripe / Resend keys are all optional), follow **[Local Development](docs/LOCAL_DEVELOPMENT.md)**.

**1. Clone the repository**
Short version:

```bash
git clone https://github.com/superset-sh/superset.git
cd superset
```

**2. Set up environment variables** (choose one):

Option A: Full setup
```bash
cp .env.example .env
# Edit .env and fill in the values
```

Option B: Skip env validation (for quick local testing)
```bash
cp .env.example .env
echo 'SKIP_ENV_VALIDATION=1' >> .env
```

**3. Set up Caddy** (reverse proxy for Electric SQL streams):

```bash
# Install caddy: brew install caddy (macOS) or see https://caddyserver.com/docs/install
cp Caddyfile.example Caddyfile

# Without this, Chromium rejects https://localhost:* with ERR_CERT_AUTHORITY_INVALID.
# Prompts for sudo once.
caddy trust
```

**4. Install dependencies and run**

```bash
bun install
bun run dev
bun setup:local
bun dev
```

**5. Build the desktop app**
`bun setup:local` copies local examples, assigns this worktree its own local database and desktop state, starts Docker Postgres/Electric, trusts Caddy's local CA, and runs migrations. It does not overwrite internal `.env` files. The desktop window opens auto-signed-in as `admin@local.test`, with state isolated under `~/.superset-local-dev-*` so source builds do not reuse production or canary desktop state. See [Local Development](docs/LOCAL_DEVELOPMENT.md) for details and troubleshooting.

To build a distributable desktop app:

```bash
bun run build
open apps/desktop/release
```

</details>

## Keyboard Shortcuts

All shortcuts are customizable via **Settings > Keyboard Shortcuts** (`⌘/`). See [full documentation](https://docs.superset.sh/keyboard-shortcuts).
Expand Down
5 changes: 4 additions & 1 deletion apps/admin/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { shouldSkipEnvValidation } from "@superset/shared/deployment-profile";
import { createEnv } from "@t3-oss/env-nextjs";
import { vercel } from "@t3-oss/env-nextjs/presets-zod";
import { z } from "zod";

const skipValidation = shouldSkipEnvValidation();

export const env = createEnv({
extends: [vercel()],
shared: {
Expand Down Expand Up @@ -49,6 +52,6 @@ export const env = createEnv({
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
},

skipValidation: !!process.env.SKIP_ENV_VALIDATION,
skipValidation,
emptyStringAsUndefined: true,
});
1 change: 1 addition & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"clean": "git clean -xdf .cache .next .turbo node_modules",
"dev": "dotenv -e ../../.env -- sh -c 'exec next dev --port ${API_PORT:-3001}'",
"start": "next start --port 3001",
"test": "bun test",
"typecheck": "tsc --noEmit"
},
"dependencies": {
Expand Down
14 changes: 9 additions & 5 deletions apps/api/src/app/api/automations/evaluate/route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { dbWs } from "@superset/db/client";
import { automations } from "@superset/db/schema";
import { nextOccurrenceAfter } from "@superset/shared/rrule";
import { Client, Receiver } from "@upstash/qstash";
import { Receiver } from "@upstash/qstash";
import { and, eq, lte } from "drizzle-orm";

import { env } from "@/env";
import { qstash } from "@/lib/qstash";

export const dynamic = "force-dynamic";

const qstash = new Client({
token: env.QSTASH_TOKEN,
baseUrl: env.QSTASH_URL,
});
const receiver = new Receiver({
currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY,
nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY,
Expand Down Expand Up @@ -53,6 +50,13 @@ export async function POST(request: Request): Promise<Response> {
return Response.json({ enqueued: 0 });
}

if (!qstash) {
return Response.json(
{ error: "QSTASH_TOKEN is required to enqueue automation jobs" },
{ status: 503 },
);
}

await qstash.batchJSON(
due.map((automation) => {
const scheduledFor = bucketToMinute(automation.nextRunAt);
Expand Down
34 changes: 23 additions & 11 deletions apps/api/src/app/api/github/callback/route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { db } from "@superset/db/client";
import { githubInstallations, members } from "@superset/db/schema";
import { Client } from "@upstash/qstash";
import { and, eq, ne } from "drizzle-orm";

import { env } from "@/env";
import { verifySignedState } from "@/lib/oauth-state";
import { qstash, requireQstash } from "@/lib/qstash";
import { githubApp } from "../octokit";

const qstash = new Client({ token: env.QSTASH_TOKEN });

/**
* Callback handler for GitHub App installation.
* GitHub redirects here after the user installs/configures the app.
Expand Down Expand Up @@ -142,14 +140,28 @@ export async function GET(request: Request) {

// Queue initial sync job
try {
await qstash.publishJSON({
url: `${env.NEXT_PUBLIC_API_URL}/api/github/jobs/initial-sync`,
body: {
installationDbId: savedInstallation.id,
organizationId,
},
retries: 3,
});
const syncUrl = `${env.NEXT_PUBLIC_API_URL}/api/github/jobs/initial-sync`;
const syncBody = {
installationDbId: savedInstallation.id,
organizationId,
};

if (env.NODE_ENV === "development" && !qstash) {
const response = await fetch(syncUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(syncBody),
});
if (!response.ok) {
throw new Error(`Local sync request failed: ${response.status}`);
}
} else {
await requireQstash("github/callback").publishJSON({
url: syncUrl,
body: syncBody,
retries: 3,
});
}
} catch (error) {
console.error(
"[github/callback] Failed to queue initial sync job:",
Expand Down
19 changes: 19 additions & 0 deletions apps/api/src/app/api/health/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
getDeploymentProfile,
isStrictProfile,
} from "@superset/shared/deployment-profile";
import { NextResponse } from "next/server";
import { getIntegrationStatuses } from "../../../lib/integration-status";

export function GET() {
const profile = getDeploymentProfile();
if (isStrictProfile(profile)) {
return NextResponse.json({ ok: true });
}

return NextResponse.json({
ok: true,
profile,
integrations: getIntegrationStatuses(),
});
}
Loading