Skip to content
Open
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
4 changes: 2 additions & 2 deletions apps/web/src/__tests__/middleware-security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
* use the REAL csrf module so the assertions are about the middleware's actual
* behaviour rather than about a stub.
*
* Covers outpost#225 item 1: a convenience early-return (static assets / any path
* Covers the ordering guarantee: a convenience early-return (static assets / any path
* containing a dot) sat above both the auth check and the CSRF check, so
* `PATCH /api/accounts/x.json` reached the handler with neither applied.
*/
Expand Down Expand Up @@ -66,7 +66,7 @@ function responseStub(type: string) {
return { type, cookies: { set: vi.fn() } };
}

describe('middleware security ordering (outpost#225)', () => {
describe('middleware security ordering', () => {
beforeEach(() => {
mockGetToken.mockReset();
mockNext.mockReset();
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/__tests__/templates-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
import type { NextRequest } from 'next/server';

/**
* Template routes: persistence and preview fidelity (outpost#226).
* Template routes: persistence and preview fidelity.
*
* Before this suite, all three write paths were stubs. `PUT` validated its input
* and returned a success body without touching the database, while the UI reported
Expand Down Expand Up @@ -84,7 +84,7 @@ function routeParams(slug: string) {
return { params: Promise.resolve({ slug }) };
}

describe('template persistence and preview (outpost#226)', () => {
describe('template persistence and preview', () => {
beforeEach(() => {
mockGetServerSession.mockReset();
mockGetServerSession.mockResolvedValue(ADMIN_SESSION);
Expand Down
12 changes: 6 additions & 6 deletions apps/web/src/__tests__/templates-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import TemplatesPage from '@/app/settings/templates/page';

/**
* Template editor: preview containment and draft fidelity (outpost#226).
* Template editor: preview containment and draft fidelity.
*
* The preview rendered author-authored HTML through `dangerouslySetInnerHTML` with no
* sanitisation. Templates are dashboard-editable, so that is a STORED sink — whatever
Expand Down Expand Up @@ -80,7 +80,7 @@ async function openPreview() {
await waitFor(() => expect(screen.getByTitle(/preview/i)).toBeTruthy());
}

describe('template preview containment (outpost#226)', () => {
describe('template preview containment', () => {
beforeEach(() => {
mockApiFetch.mockReset();
routeApiFetch();
Expand Down Expand Up @@ -123,7 +123,7 @@ describe('template preview containment (outpost#226)', () => {
});
});

describe('the editor reports what the server actually said (outpost#226)', () => {
describe('the editor reports what the server actually said', () => {
beforeEach(() => {
mockApiFetch.mockReset();
});
Expand Down Expand Up @@ -187,7 +187,7 @@ describe('the editor reports what the server actually said (outpost#226)', () =>
// "Template saved successfully" was true about the row and false about the thing
// the author cared about. These pin the honest copy, because the dishonest version
// is the shorter and more natural string to write.
describe('the editor does not claim more than a save delivers (outpost#226)', () => {
describe('the editor does not claim more than a save delivers', () => {
beforeEach(() => {
mockApiFetch.mockReset();
});
Expand Down Expand Up @@ -224,7 +224,7 @@ describe('the editor does not claim more than a save delivers (outpost#226)', ()
});
});

describe('reset gives the author feedback (outpost#226)', () => {
describe('reset gives the author feedback', () => {
beforeEach(() => {
mockApiFetch.mockReset();
});
Expand Down Expand Up @@ -261,7 +261,7 @@ describe('reset gives the author feedback (outpost#226)', () => {
});
});

describe('preview shows the unsaved draft (outpost#226)', () => {
describe('preview shows the unsaved draft', () => {
beforeEach(() => {
mockApiFetch.mockReset();
routeApiFetch();
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/app/settings/templates/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default function TemplatesPage() {
// shape as the rest of this screen's history. Wiring the lookup is
// tracked separately, and per outpost#253 would not make an edited
// template reach an invitee today either.
setSuccess('Saved. Not yet used for outgoing email — see outpost#226.');
setSuccess('Saved. Not yet used for outgoing email — see outpost#279.');
} catch (err) {
setError(err instanceof Error ? err.message : 'Save failed');
} finally {
Expand Down Expand Up @@ -174,7 +174,7 @@ export default function TemplatesPage() {
<div>
<PageHeader
title="Email Templates"
description="Edit and preview outbound email templates. Saved edits are not yet used for outgoing email — see outpost#226."
description="Edit and preview outbound email templates. Saved edits are not yet used for outgoing email — see outpost#279."
icon={Mail}
breadcrumbs={[{ label: 'Settings', href: '/settings' }, { label: 'Templates' }]}
/>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const PUBLIC_PATHS = ['/login', '/api/auth', '/setup', '/api/setup', '/api/healt
* This replaces a bare `pathname.includes('.')` check. That heuristic treated ANY
* dotted path as a static asset, and because it ran ahead of the auth and CSRF
* checks below, `PATCH /api/accounts/x.json` reached the handler with neither
* applied (outpost#225).
* applied.
*
* Deliberately an allowlist of extensions rather than "has a dot": a request path
* is attacker-controlled, so anything that decides "skip the security checks" has
Expand Down
Loading