diff --git a/apps/agent-worker/src/redact.ts b/apps/agent-worker/src/redact.ts index b2e6756..30c8323 100644 --- a/apps/agent-worker/src/redact.ts +++ b/apps/agent-worker/src/redact.ts @@ -1,8 +1,11 @@ -const secretPatterns = [ - /ghs_[A-Za-z0-9_]+/g, - /github_pat_[A-Za-z0-9_]+/g, - /sk-[A-Za-z0-9_-]+/g, - /(client_secret|auth_secret|api_key|token|password)=([^ \n\r]+)/gi, +const secretPatterns: { pattern: RegExp; replacement: string }[] = [ + { pattern: /ghs_[A-Za-z0-9_]+/g, replacement: '[redacted]' }, + { pattern: /github_pat_[A-Za-z0-9_]+/g, replacement: '[redacted]' }, + { pattern: /sk-[A-Za-z0-9_-]+/g, replacement: '[redacted]' }, + { + pattern: /(client_secret|auth_secret|api_key|token|password)=([^ \n\r]+)/gi, + replacement: '$1=[redacted]', + }, ]; export const createRedactor = (values: string[]) => { @@ -12,8 +15,8 @@ export const createRedactor = (values: string[]) => { for (const secret of secrets) { output = output.split(secret).join('[redacted]'); } - for (const pattern of secretPatterns) { - output = output.replace(pattern, '$1=[redacted]'); + for (const { pattern, replacement } of secretPatterns) { + output = output.replace(pattern, replacement); } return output; }; diff --git a/apps/agent-worker/tests/unit/redact.test.ts b/apps/agent-worker/tests/unit/redact.test.ts new file mode 100644 index 0000000..c282aab --- /dev/null +++ b/apps/agent-worker/tests/unit/redact.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, test } from 'vitest'; + +import { createRedactor } from '../../src/redact'; + +describe('createRedactor', () => { + test('redacts group-less token patterns without emitting a literal $1', () => { + const redact = createRedactor([]); + const output = redact('token ghs_ABC123 and sk-xyz789 here'); + + expect(output).toContain('[redacted]'); + expect(output).not.toContain('$1'); + expect(output).not.toContain('ghs_ABC123'); + expect(output).not.toContain('sk-xyz789'); + }); + + test('redacts github_pat_ tokens to [redacted]', () => { + const redact = createRedactor([]); + const output = redact('github_pat_ABCDEF123456'); + + expect(output).toBe('[redacted]'); + expect(output).not.toContain('$1'); + }); + + test('keeps the key= prefix for key=value secrets', () => { + const redact = createRedactor([]); + + expect(redact('api_key=secret')).toBe('api_key=[redacted]'); + expect(redact('password=hunter2')).toBe('password=[redacted]'); + }); + + test('redacts caller-supplied secret values verbatim', () => { + const redact = createRedactor(['super-secret-value']); + + expect(redact('the value is super-secret-value')).toBe( + 'the value is [redacted]', + ); + }); +}); diff --git a/apps/next/src/app/(app)/agents/page.tsx b/apps/next/src/app/(app)/agents/page.tsx deleted file mode 100644 index cff9752..0000000 --- a/apps/next/src/app/(app)/agents/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { redirect } from 'next/navigation'; - -const AgentsRedirectPage = () => { - redirect('/threads?source=user_request'); -}; - -export default AgentsRedirectPage; diff --git a/apps/next/src/app/(app)/settings/ai/page.tsx b/apps/next/src/app/(app)/settings/ai/page.tsx deleted file mode 100644 index 35a52e3..0000000 --- a/apps/next/src/app/(app)/settings/ai/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from 'next/navigation'; - -const AiSettingsPage = () => redirect('/settings/ai-providers'); - -export default AiSettingsPage; diff --git a/apps/next/src/app/(app)/updates/page.tsx b/apps/next/src/app/(app)/updates/page.tsx deleted file mode 100644 index 02d0364..0000000 --- a/apps/next/src/app/(app)/updates/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { redirect } from 'next/navigation'; - -const UpdatesRedirectPage = () => { - redirect('/threads?source=upstream_update'); -}; - -export default UpdatesRedirectPage; diff --git a/apps/next/src/app/(auth)/profile/layout.tsx b/apps/next/src/app/(auth)/profile/layout.tsx deleted file mode 100644 index f4b5217..0000000 --- a/apps/next/src/app/(auth)/profile/layout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { Metadata } from 'next'; -import { redirect } from 'next/navigation'; -import { isAuthenticatedNextjs } from '@convex-dev/auth/nextjs/server'; - -export const generateMetadata = (): Metadata => { - return { - title: 'Profile', - robots: { - index: false, - follow: false, - googleBot: { - index: false, - follow: false, - }, - }, - }; -}; - -const ProfileLayout = async ({ - children, -}: Readonly<{ children: React.ReactNode }>) => { - if (!(await isAuthenticatedNextjs())) redirect('/sign-in'); - return <>{children}; -}; -export default ProfileLayout; diff --git a/apps/next/src/app/(auth)/profile/page.tsx b/apps/next/src/app/(auth)/profile/page.tsx deleted file mode 100644 index e38982b..0000000 --- a/apps/next/src/app/(auth)/profile/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { redirect } from 'next/navigation'; - -const Profile = () => { - redirect('/settings/profile'); -}; -export default Profile; diff --git a/apps/next/src/components/landing/tech-stack.tsx b/apps/next/src/components/landing/tech-stack.tsx deleted file mode 100644 index 1cc6140..0000000 --- a/apps/next/src/components/landing/tech-stack.tsx +++ /dev/null @@ -1,75 +0,0 @@ -const techStack = [ - { - category: 'Frontend', - technologies: [ - { name: 'Next.js 16', description: 'React framework with App Router' }, - { name: 'Expo 54', description: 'React Native framework' }, - { name: 'React 19', description: 'Latest React with Server Components' }, - { - name: 'Tailwind CSS v4', - description: 'Utility-first CSS framework', - }, - { name: 'shadcn/ui', description: 'Beautiful component library' }, - ], - }, - { - category: 'Backend', - technologies: [ - { name: 'Convex', description: 'Self-hosted reactive backend' }, - { - name: '@convex-dev/auth', - description: 'Multi-provider authentication', - }, - { name: 'UseSend', description: 'Self-hosted email service' }, - { name: 'File Storage', description: 'Built-in file uploads' }, - ], - }, - { - category: 'Developer Tools', - technologies: [ - { name: 'Turborepo', description: 'High-performance build system' }, - { name: 'TypeScript', description: 'Type-safe development' }, - { name: 'Bun', description: 'Fast package manager and runtime' }, - { name: 'ESLint + Prettier', description: 'Code quality tools' }, - { name: 'Docker', description: 'Containerized deployment' }, - ], - }, -]; - -export const TechStack = () => ( -
-
-
-
-

- Modern Tech Stack -

-

- Built with the latest and greatest tools for maximum productivity - and performance. -

-
- -
- {techStack.map((stack) => ( -
-

{stack.category}

-
    - {stack.technologies.map((tech) => ( -
  • -
    - {tech.name} -
    -
    - {tech.description} -
    -
  • - ))} -
-
- ))} -
-
-
-
-); diff --git a/apps/next/src/components/spoons/spoon-agent-settings-form.tsx b/apps/next/src/components/spoons/spoon-agent-settings-form.tsx index d290e8a..c3f8945 100644 --- a/apps/next/src/components/spoons/spoon-agent-settings-form.tsx +++ b/apps/next/src/components/spoons/spoon-agent-settings-form.tsx @@ -33,7 +33,6 @@ const runtimeLabels: Record = { }; type AgentSettings = { - _id?: Id<'spoonAgentSettings'>; enabled: boolean; runtime?: RuntimeName | 'openai_direct'; defaultBaseBranch?: string; diff --git a/apps/next/src/components/threads/thread-workspace-form.tsx b/apps/next/src/components/threads/thread-workspace-form.tsx index c102765..3c56ea3 100644 --- a/apps/next/src/components/threads/thread-workspace-form.tsx +++ b/apps/next/src/components/threads/thread-workspace-form.tsx @@ -34,7 +34,6 @@ const runtimeLabels: Record = { }; type AgentSettings = { - _id?: Id<'spoonAgentSettings'>; defaultBaseBranch?: string; runtime?: RuntimeName | 'openai_direct'; agentModel: string; diff --git a/apps/next/src/proxy.ts b/apps/next/src/proxy.ts index e680df6..a339e84 100644 --- a/apps/next/src/proxy.ts +++ b/apps/next/src/proxy.ts @@ -8,12 +8,9 @@ const isAuthRoute = createRouteMatcher(['/sign-in', '/forgot-password']); const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/spoons(.*)', - '/updates(.*)', - '/agents(.*)', '/threads(.*)', '/github(.*)', '/settings(.*)', - '/profile(.*)', ]); export default convexAuthNextjsMiddleware(