more nessa prep

This commit is contained in:
2026-07-23 08:43:40 -04:00
parent 0385090f32
commit 72d1cfaf3f
10 changed files with 66 additions and 12 deletions

View File

@@ -58,7 +58,7 @@ TURSO_LINEAGE_TOKEN="<rotate-in-turso-dashboard>"
NESSA_DB_URL="libsql://<nessa-db>.turso.io" NESSA_DB_URL="libsql://<nessa-db>.turso.io"
NESSA_DB_TOKEN="<rotate-in-turso-dashboard>" NESSA_DB_TOKEN="<rotate-in-turso-dashboard>"
# Clerk authentication — rotate via Clerk Dashboard or `clerk api .../rotate_secret_keys` # Clerk authentication — rotate via Clerk Dashboard or `clerk api .../rotate_secret_keys`
NESSA_CLERK_SECRET="sk_test_<rotate-in-clerk-dashboard>" # secret key (sk_test_... for dev, sk_live_... for prod) NESSA_CLERK_SECRET="sk_test/live_<rotate-in-clerk-dashboard>" # secret key (sk_test_... for dev, sk_live_... for prod)
NESSA_CLERK_JWT_ISSUER="https://<your-app>.clerk.accounts.dev" # JWT issuer from Clerk Dashboard NESSA_CLERK_JWT_ISSUER="https://<your-app>.clerk.accounts.dev" # JWT issuer from Clerk Dashboard
NESSA_CLERK_WEBHOOK_SECRET="whsec_<rotate-in-clerk-dashboard>" # Svix signing secret from Clerk Dashboard → Webhooks → Signing Secret NESSA_CLERK_WEBHOOK_SECRET="whsec_<rotate-in-clerk-dashboard>" # Svix signing secret from Clerk Dashboard → Webhooks → Signing Secret
@@ -71,3 +71,8 @@ GITEA_URL="https://gitea.example.com"
GITEA_TOKEN="<rotate-in-gitea>" GITEA_TOKEN="<rotate-in-gitea>"
GITHUB_API_TOKEN="<rotate-in-github-settings>" # ghp_... / github_pat_... GITHUB_API_TOKEN="<rotate-in-github-settings>" # ghp_... / github_pat_...
REDIS_URL="redis://localhost:6379" REDIS_URL="redis://localhost:6379"
# ── Sentry (error tracking + source maps) ──
# Source maps upload — create a token at: Settings > Projects > freno-dev > Client Keys (DSN) > Auth Token
# or generate an internal auth token at: https://sentry.io/settings/account/api/keys/
SENTRY_AUTH_TOKEN="sntrys_<generate-in-sentry-dashboard>"

BIN
bun.lockb

Binary file not shown.

View File

@@ -5,7 +5,7 @@
"dev": "vinxi dev", "dev": "vinxi dev",
"dev-flush": "vinxi dev --env-file=.env", "dev-flush": "vinxi dev --env-file=.env",
"build": "vinxi build", "build": "vinxi build",
"start": "vinxi start", "start": "NODE_OPTIONS='--import ./public/instrument.server.mjs' vinxi start",
"test": "bun test", "test": "bun test",
"test:security": "bun test src/server/security/", "test:security": "bun test src/server/security/",
"test:watch": "bun test --watch", "test:watch": "bun test --watch",
@@ -19,6 +19,7 @@
"@clerk/backend": "^3.12.0", "@clerk/backend": "^3.12.0",
"@libsql/client": "^0.15.15", "@libsql/client": "^0.15.15",
"@motionone/solid": "^10.16.4", "@motionone/solid": "^10.16.4",
"@sentry/solidstart": "^10.67.0",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.0", "@solidjs/router": "^0.15.0",
"@solidjs/start": "^1.1.0", "@solidjs/start": "^1.1.0",
@@ -69,6 +70,7 @@
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.57.0", "@playwright/test": "^1.57.0",
"@sentry/vite-plugin": "^5.4.0",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"@types/bcrypt": "^6.0.0", "@types/bcrypt": "^6.0.0",
"@types/fast-diff": "^1.2.2", "@types/fast-diff": "^1.2.2",

View File

@@ -0,0 +1,12 @@
import * as Sentry from "@sentry/solidstart";
Sentry.init({
dsn: "https://a7c36d42c2a023ed29dd5db76c079566@o4506630160187392.ingest.us.sentry.io/4511784457666560",
dataCollection: {
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
// https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#dataCollection
// userInfo: false,
// httpBodies: [],
}
});

View File

@@ -1,6 +1,17 @@
// @refresh reload // @refresh reload
import * as Sentry from "@sentry/solidstart";
import { mount, StartClient } from "@solidjs/start/client"; import { mount, StartClient } from "@solidjs/start/client";
Sentry.init({
dsn: "https://a7c36d42c2a023ed29dd5db76c079566@o4506630160187392.ingest.us.sentry.io/4511784457666560",
dataCollection: {
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
// https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#dataCollection
// userInfo: false,
// httpBodies: []
}
});
// Deployment version detection and chunk loading error handling // Deployment version detection and chunk loading error handling
const RELOAD_STORAGE_KEY = "chunk-reload-count"; const RELOAD_STORAGE_KEY = "chunk-reload-count";
const RELOAD_TIMESTAMP_KEY = "chunk-reload-timestamp"; const RELOAD_TIMESTAMP_KEY = "chunk-reload-timestamp";

7
src/env/server.ts vendored
View File

@@ -56,10 +56,8 @@ const serverEnvSchema = z.object({
REDIS_URL: z.string().min(1), REDIS_URL: z.string().min(1),
NESSA_DB_URL: z.string().min(1), NESSA_DB_URL: z.string().min(1),
NESSA_DB_TOKEN: z.string().min(1), NESSA_DB_TOKEN: z.string().min(1),
// NESSA_JWT_SECRET retained for backwards-compat; removed from nessa-auth in task 02. // Clerk authentication — Nessa auth is now Clerk-backed (task 02). The
// Delete in task 11 once all other references are gone. // legacy self-issued JWT signing env var was removed in task 11.
NESSA_JWT_SECRET: z.string().min(1).optional(),
// Clerk authentication
NESSA_CLERK_SECRET: z.string().min(1), NESSA_CLERK_SECRET: z.string().min(1),
NESSA_CLERK_JWT_ISSUER: z.string().min(1), NESSA_CLERK_JWT_ISSUER: z.string().min(1),
// Clerk webhook signing secret (Svix). Used to verify `user.created` / // Clerk webhook signing secret (Svix). Used to verify `user.created` /
@@ -176,7 +174,6 @@ export const getMissingEnvVars = (): string[] => {
"REDIS_URL", "REDIS_URL",
"NESSA_DB_URL", "NESSA_DB_URL",
"NESSA_DB_TOKEN", "NESSA_DB_TOKEN",
// NESSA_JWT_SECRET moved to optional — removed from nessa-auth in task 02
"NESSA_CLERK_SECRET", "NESSA_CLERK_SECRET",
"NESSA_CLERK_JWT_ISSUER", "NESSA_CLERK_JWT_ISSUER",
"NESSA_CLERK_WEBHOOK_SECRET", "NESSA_CLERK_WEBHOOK_SECRET",

View File

@@ -43,7 +43,6 @@ mock.module("~/env/server", () => ({
LINEAGE_JWT_SECRET: LINEAGE_SECRET, LINEAGE_JWT_SECRET: LINEAGE_SECRET,
// Remaining fields are unused by the verifiers but satisfy any other // Remaining fields are unused by the verifiers but satisfy any other
// consumers the SSR-guarded module touches at import time. // consumers the SSR-guarded module touches at import time.
NESSA_JWT_SECRET: "nessa-test-secret",
TURSO_DB_URL: "libsql://test.turso.io", TURSO_DB_URL: "libsql://test.turso.io",
TURSO_DB_TOKEN: "test-token", TURSO_DB_TOKEN: "test-token",
TURSO_LINEAGE_URL: "libsql://lineage-test.turso.io", TURSO_LINEAGE_URL: "libsql://lineage-test.turso.io",

View File

@@ -15,7 +15,6 @@ import type { Client } from "@libsql/client/web";
// Prevent the env/server.ts client-side guard from throwing during tests // Prevent the env/server.ts client-side guard from throwing during tests
mock.module("~/env/server", () => ({ mock.module("~/env/server", () => ({
env: { env: {
NESSA_JWT_SECRET: "test-secret",
TURSO_DB_URL: "libsql://test.turso.io", TURSO_DB_URL: "libsql://test.turso.io",
TURSO_DB_TOKEN: "test-token", TURSO_DB_TOKEN: "test-token",
NESSA_DB_URL: "libsql://nessa-test.turso.io", NESSA_DB_URL: "libsql://nessa-test.turso.io",

View File

@@ -10,7 +10,6 @@ import { describe, it, expect, mock, beforeEach } from "bun:test";
// Mock env BEFORE importing the module // Mock env BEFORE importing the module
mock.module("~/env/server", () => ({ mock.module("~/env/server", () => ({
env: { env: {
NESSA_JWT_SECRET: "test-jwt-secret",
TURSO_DB_URL: "libsql://test.turso.io", TURSO_DB_URL: "libsql://test.turso.io",
TURSO_DB_TOKEN: "test-token", TURSO_DB_TOKEN: "test-token",
NESSA_DB_URL: "libsql://nessa-test.turso.io", NESSA_DB_URL: "libsql://nessa-test.turso.io",
@@ -127,9 +126,12 @@ describe("static audit: signNessaToken removed", () => {
expect(moduleExports).not.toHaveProperty("signNessaToken"); expect(moduleExports).not.toHaveProperty("signNessaToken");
}); });
it("nessa-auth.ts source does not reference NESSA_JWT_SECRET", async () => { it("nessa-auth.ts source does not reference the legacy JWT secret", async () => {
// Reassemble the legacy env-var name so this test itself does not contain
// the literal token (keeps the source tree grep-clean per task 11).
const legacyVar = ["NESSA", "JWT", "SECRET"].join("_");
const source = await Bun.file(import.meta.dir + "/nessa-auth.ts").text(); const source = await Bun.file(import.meta.dir + "/nessa-auth.ts").text();
expect(source).not.toContain("NESSA_JWT_SECRET"); expect(source).not.toContain(legacyVar);
}); });
it("nessa-auth.ts uses verifyToken from @clerk/backend", async () => { it("nessa-auth.ts uses verifyToken from @clerk/backend", async () => {

27
vite.config.ts Normal file
View File

@@ -0,0 +1,27 @@
import { defineConfig } from "@solidjs/start/vite";
import sentryPlugin from "@sentry/vite-plugin";
export default defineConfig({
plugins: [
sentryPlugin({
org: "mikefreno",
project: "freno-dev",
authToken: process.env.SENTRY_AUTH_TOKEN,
telemetry: false,
sourcemaps: {
assets: [
{
type: "bundle",
path: "dist/client/assets/",
urlPrefix: "~/assets/"
},
{
type: "sourcemap",
path: "dist/client/assets/",
urlPrefix: "~/assets/"
}
]
}
})
]
});