Skip to content

Commit b0e3497

Browse files
Merge origin/main into fix/decrypt-progress-a11y
Resolve conflict in DecryptionProgress.svelte. Main (#250) already added status-message a11y by putting role="status" on the label paragraph; kept that to avoid a duplicate live region on the container. Kept this branch's aria-busy="true" on the indeterminate progressbar. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 parents 5e097f9 + e410c69 commit b0e3497

45 files changed

Lines changed: 4201 additions & 437 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
- run: npx svelte-kit sync
3232
- run: npx svelte-check --threshold warning
3333

34-
# Run prettier --check and eslint.
34+
# Run prettier --check, eslint, and stylelint.
3535
lint:
3636
name: Lint
3737
runs-on: ubuntu-latest
@@ -44,6 +44,8 @@ jobs:
4444
- run: npm ci
4545
- run: npx svelte-kit sync
4646
- run: npm run lint
47+
# Fail on references to undefined CSS custom properties (e.g. typo'd --pg-* tokens).
48+
- run: npm run lint:css
4749

4850
# Create a GitHub release (and tag) when conventional commits warrant one.
4951
release-please:

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ package
77
.vscode
88
.env.local
99
.env.*.local
10-
*.pem
10+
11+
# Playwright
12+
/test-results
13+
/playwright-report
14+
/blob-report
15+
/playwright/.cache
16+
17+
*.pem
1118
*.pub
1219
*.sec
1320

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ build/
77
.svelte-kit/
88
dist/
99
node_modules/
10+
test-results/
11+
playwright-report/
1012

1113
# Lockfiles
1214
package-lock.json

docker-compose.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ services:
1818
- ./cryptify/conf/config.dev.toml:/app/config.toml:ro
1919
- ./cryptify/src:/app/src
2020
- ./cryptify/templates:/app/templates
21+
# build.rs feeds `PG_CORE_VERSION` (used by the X-PostGuard
22+
# mail header) from Cargo.lock at compile time. Both files
23+
# need to be visible inside the container, or cargo bails
24+
# on `env!("PG_CORE_VERSION")`.
25+
- ./cryptify/build.rs:/app/build.rs:ro
26+
- ./cryptify/Cargo.lock:/app/Cargo.lock:ro
2127
- cryptify-target:/app/target
2228
environment:
2329
- RUST_LOG=info
@@ -91,6 +97,164 @@ services:
9197
networks:
9298
- postguard
9399

100+
# GlitchTip — open-source, Sentry-compatible error tracker.
101+
# Reports posted by the website's CrashReport button land here.
102+
# UI at http://localhost:8000 (override via GLITCHTIP_PORT if 8000 is taken).
103+
# On first boot, create an account and a project; the DSN goes into
104+
# APP_CONFIG.GLITCHTIP_DSN (see src/lib/env.ts).
105+
glitchtip-postgres:
106+
image: postgres:16-alpine
107+
environment:
108+
- POSTGRES_HOST_AUTH_METHOD=trust
109+
- POSTGRES_DB=glitchtip
110+
volumes:
111+
- glitchtip-pg:/var/lib/postgresql/data
112+
networks:
113+
- postguard
114+
115+
glitchtip-redis:
116+
image: valkey/valkey:8-alpine
117+
networks:
118+
- postguard
119+
120+
glitchtip-web:
121+
image: glitchtip/glitchtip:v5
122+
depends_on:
123+
- glitchtip-postgres
124+
- glitchtip-redis
125+
environment:
126+
- DATABASE_URL=postgres://postgres@glitchtip-postgres:5432/glitchtip
127+
- REDIS_URL=redis://glitchtip-redis:6379/0
128+
- SECRET_KEY=${GLITCHTIP_SECRET_KEY:-dev-only-change-me}
129+
- PORT=8001
130+
- DEFAULT_FROM_EMAIL=noreply@postguard.local
131+
- GLITCHTIP_DOMAIN=http://localhost:8001
132+
- ENABLE_OPEN_USER_REGISTRATION=true
133+
ports:
134+
- '8001:8001'
135+
volumes:
136+
- glitchtip-uploads:/code/uploads
137+
networks:
138+
- postguard
139+
140+
glitchtip-worker:
141+
image: glitchtip/glitchtip:v5
142+
command: ./bin/run-celery-with-beat.sh
143+
# `glitchtip-web` runs Django migrations on startup. Without
144+
# depending on it, the worker's celery-beat starts firing
145+
# scheduled jobs (uptime-dispatch-checks etc.) before the
146+
# tables exist and crashes with `relation "uptime_monitor"
147+
# does not exist`. The web container has no healthcheck, so
148+
# this is a `service_started` ordering rather than a true
149+
# readiness gate — good enough on a single host where the
150+
# web container reaches Postgres in a few seconds.
151+
depends_on:
152+
- glitchtip-postgres
153+
- glitchtip-redis
154+
- glitchtip-web
155+
- glitchtip-init
156+
environment:
157+
- DATABASE_URL=postgres://postgres@glitchtip-postgres:5432/glitchtip
158+
- REDIS_URL=redis://glitchtip-redis:6379/0
159+
- SECRET_KEY=${GLITCHTIP_SECRET_KEY:-dev-only-change-me}
160+
volumes:
161+
- glitchtip-uploads:/code/uploads
162+
networks:
163+
- postguard
164+
165+
# One-shot: applies migrations and creates the dev superuser if it
166+
# doesn't already exist. Runs to completion and exits. Idempotent —
167+
# `createsuperuser --noinput` errors on a duplicate, which we
168+
# swallow so subsequent `up`s remain no-ops. Override credentials
169+
# by exporting GLITCHTIP_ADMIN_EMAIL / GLITCHTIP_ADMIN_PASSWORD.
170+
glitchtip-init:
171+
image: glitchtip/glitchtip:v5
172+
depends_on:
173+
- glitchtip-postgres
174+
environment:
175+
- DATABASE_URL=postgres://postgres@glitchtip-postgres:5432/glitchtip
176+
- REDIS_URL=redis://glitchtip-redis:6379/0
177+
- SECRET_KEY=${GLITCHTIP_SECRET_KEY:-dev-only-change-me}
178+
# python-email-validator (used by GlitchTip's Pydantic response
179+
# schemas) rejects `local`, `localhost`, `test`, `invalid`,
180+
# `arpa`, `onion` TLDs as special-use — so `/api/0/users/me/`
181+
# 500s if the superuser email lands on one of those. `.dev` is
182+
# a real public TLD and not on that list.
183+
- DJANGO_SUPERUSER_EMAIL=${GLITCHTIP_ADMIN_EMAIL:-admin@postguard.dev}
184+
- DJANGO_SUPERUSER_PASSWORD=${GLITCHTIP_ADMIN_PASSWORD:-devpass1}
185+
# Bootstraps: migrations → superuser → PostGuard org → website
186+
# project → prints the DSN. Each step is idempotent so subsequent
187+
# `up`s remain no-ops. Paste the printed DSN into static/config.js
188+
# under `APP_CONFIG.GLITCHTIP_DSN` (or set `GLITCHTIP_DSN=…` in
189+
# .env.dev) — the DSN is stable as long as the postgres volume
190+
# survives, so this is a one-time copy.
191+
command:
192+
- sh
193+
- -c
194+
- |
195+
./manage.py migrate --noinput &&
196+
(./manage.py createsuperuser --noinput 2>/dev/null \
197+
&& echo 'glitchtip-init: superuser created' \
198+
|| echo 'glitchtip-init: superuser already exists') &&
199+
./manage.py shell -c "
200+
from django.apps import apps
201+
from django.contrib.auth import get_user_model
202+
Organization = apps.get_model('organizations_ext', 'Organization')
203+
Project = apps.get_model('projects', 'Project')
204+
ProjectKey = apps.get_model('projects', 'ProjectKey')
205+
206+
user = get_user_model().objects.get(email='$$DJANGO_SUPERUSER_EMAIL')
207+
208+
org, org_created = Organization.objects.get_or_create(
209+
slug='postguard',
210+
defaults={'name': 'PostGuard'},
211+
)
212+
if org_created:
213+
org.add_user(user)
214+
print('glitchtip-init: org PostGuard created')
215+
else:
216+
print('glitchtip-init: org PostGuard already exists')
217+
218+
project, proj_created = Project.objects.get_or_create(
219+
organization=org,
220+
slug='postguard-website',
221+
defaults={'name': 'postguard-website', 'platform': 'javascript'},
222+
)
223+
if proj_created:
224+
print('glitchtip-init: project postguard-website created')
225+
else:
226+
print('glitchtip-init: project postguard-website already exists')
227+
228+
# Pin a deterministic public_key so the DSN survives a
229+
# full volume wipe. Without this, a fresh postgres volume
230+
# regenerates the UUID and any hardcoded DSN in
231+
# static/config.js silently goes stale.
232+
#
233+
# GlitchTip auto-creates a default ProjectKey when a
234+
# Project is saved, so on a fresh volume the get_or_create
235+
# below returns that auto-created key (key_created=False)
236+
# and the defaults= clause is ignored. The `not key_created`
237+
# branch catches that case and rewrites public_key to
238+
# DEV_KEY.
239+
import uuid
240+
DEV_KEY = uuid.UUID('1d8ea2a49c904f079b116550780c0ece')
241+
key, key_created = ProjectKey.objects.get_or_create(
242+
project=project,
243+
defaults={'public_key': DEV_KEY},
244+
)
245+
if not key_created and key.public_key != DEV_KEY:
246+
key.public_key = DEV_KEY
247+
key.save()
248+
dsn = f'http://{key.public_key.hex}@localhost:8001/{project.id}'
249+
print('========================================')
250+
print('glitchtip-init: DSN (already set in static/config.js):')
251+
print(f' {dsn}')
252+
print('========================================')
253+
"
254+
restart: 'no'
255+
networks:
256+
- postguard
257+
94258
# Nginx reverse proxy
95259
nginx:
96260
image: nginx:alpine
@@ -114,3 +278,5 @@ volumes:
114278
cryptify-data:
115279
cryptify-target:
116280
postguard-pkg-target:
281+
glitchtip-pg:
282+
glitchtip-uploads:

0 commit comments

Comments
 (0)