Re-pin to the cached chromium-1243 revision; full E2E suite green on 1.63.0. Approval recorded in the PLAN.md review history. LLM-Generated: true
123 lines
6.6 KiB
Markdown
123 lines
6.6 KiB
Markdown
# PLAN — Developer Homepage
|
|
|
|
**Status:** live static site · **Last reviewed:** 2026-09-18 (security & code-quality audit)
|
|
|
|
## 1. Project Identity
|
|
|
|
A single-page personal portfolio (Reese Wells — self-hosting & infrastructure)
|
|
with an interactive fake terminal (easter-egg commands, vim simulator,
|
|
achievement system). No backend, no user accounts, no PII beyond public
|
|
contact details and GPG public keys.
|
|
|
|
## 2. Assumptions & Design Principles
|
|
|
|
1. **Static first.** The site is plain HTML/CSS/JS. No runtime dependencies,
|
|
no CDNs, no build-time JS frameworks — the supply chain is the repo itself.
|
|
2. **Boring deployment.** `build.sh` → hashed `dist/` → `nginx:alpine` on
|
|
`:8080` (plain HTTP) → TLS terminated by the external Caddy reverse proxy.
|
|
3. **Test the artifact.** E2E tests run against the built `dist/`, not `src/`,
|
|
so what is tested is exactly what is deployed.
|
|
4. **Security headers are a container property.** All hardening headers are
|
|
emitted by nginx (the only thing that serves the site in production).
|
|
5. **Fun is safe.** The fake terminal's easter eggs (page-wipe, login screen,
|
|
vim) are DOM-only pranks — no real network or system effects. The only
|
|
real network behavior (curl/wget `fetch`) is being removed — see Phase 02.
|
|
|
|
## 3. Architectural Anchors (LOCKED DECISIONS)
|
|
|
|
| COMPONENT | DECISION | RATIONALE | STATUS |
|
|
|---|---|---|---|
|
|
| Frontend runtime | Vanilla HTML/CSS/JS, flat `src/*.js` files, `defer` load order | No toolchain, auditable, works with `build.sh` hashing | LOCKED (pre-existing) |
|
|
| Terminal modules | `terminal-commands.js` (canned data) · `terminal-achievements.js` · `terminal-vim.js` · `terminal.js` (core) | Flat modules keep `build.sh`'s root-level hashing working; single source of truth for command data | LOCKED (2026-09-18 refactor) |
|
|
| Build | `build.sh`: md5 content-hash cache-busting + `sed` reference rewrites → `dist/` | md5 is a cache key, not a security hash — acceptable | LOCKED (pre-existing) |
|
|
| Serving | `nginx:alpine`, `listen 8080`, plain HTTP | TLS is added by the Caddy edge in front of the container | LOCKED (pre-existing) |
|
|
| Edge | Caddy reverse proxy (Route53 DNS-validated TLS) in front of the container | HSTS/TLS are edge responsibilities | LOCKED (assumed — verify per Phase 03) |
|
|
| E2E tests | `@playwright/test` pinned **1.63.0** (matches cached chromium-1243), serves `dist/` via `python3 -m http.server 8123`, config `playwright.config.js` | Tests the deployed artifact; pinned to avoid browser re-downloads | LOCKED (2026-09-18; re-pinned 2026-09-18, user-approved — see review history) |
|
|
| Deployment | Docker image → `gitea.reeseapps.com/services/homepage` via Gitea Actions (secrets-based registry login) | Self-hosted CI | LOCKED (pre-existing) |
|
|
| Persistence | `localStorage` only (achievements, key `reese-terminal-achievements`) | No backend by design | LOCKED (pre-existing) |
|
|
|
|
## 4. High-Level Architecture
|
|
|
|
```
|
|
src/ (index.html, style.css, script.js, terminal*.js, assets)
|
|
│ build.sh (hash + rewrite)
|
|
▼
|
|
dist/ (index.html + hashed assets) ◄── playwright webServer (port 8123)
|
|
│ Dockerfile (COPY → nginx html root) ◄── tests/e2e/*.spec.js (44 tests)
|
|
▼
|
|
nginx:alpine :8080 (HTTP, security headers, cache policy)
|
|
▲
|
|
Caddy edge (TLS, HSTS) ← reeseapps.com
|
|
```
|
|
|
|
- `src/terminal.js` — terminal core: prompt loop, history, tab completion,
|
|
dispatch, expand/collapse (`expandTerminal`/`collapseTerminal`, shared with
|
|
`script.js` hero click).
|
|
- `src/terminal-commands.js` — `TERMINAL_COMMANDS` (canned outputs; values may
|
|
be functions evaluated at dispatch), `TERMINAL_COMMAND_LIST` (tab
|
|
completion), `getCommandOutput()`.
|
|
- `src/terminal-vim.js` — `launchVimSimulator({content, terminal,
|
|
mobileInput, filename, setVimMode})`.
|
|
- `src/terminal-achievements.js` — `ACHIEVEMENTS`, localStorage persistence,
|
|
toasts, hidden-section reveal, `initTerminalAchievements()`.
|
|
- `src/script.js` — nav menu, IntersectionObserver fades, server-rack
|
|
background generation, hero-click terminal toggle.
|
|
|
|
## 5. Validation / Verification Workflow
|
|
|
|
1. `./build.sh` — rebuild `dist/`.
|
|
2. `npm test` (Playwright) — 44 E2E tests against `dist/` on port 8123.
|
|
Every phase's final pass must leave the suite green.
|
|
3. `.agents/validate.sh` (installed by the `phased-execution` skill) —
|
|
must run 1 + 2 and, for Phase 03, the header checks below.
|
|
4. Container header check (Phase 03): `scripts/check-headers.sh` — builds the
|
|
image, runs it on a scratch port, asserts the four security headers on
|
|
`/`, `/index.html`, and a hashed asset.
|
|
|
|
## 6. Data Model
|
|
|
|
No server-side data. Client-side state:
|
|
|
|
| Key | Where | Shape |
|
|
|---|---|---|
|
|
| `reese-terminal-achievements` | localStorage | JSON array of achievement ids (e.g. `["time_flies","nice_try"]`) |
|
|
|
|
Session-only state (no persistence): terminal history, `isRoot`, vim state,
|
|
menu open/closed, terminal grown/collapsed.
|
|
|
|
## 7. Roadmap
|
|
|
|
| Phase | Title | Source |
|
|
|---|---|---|
|
|
| `01_fix_history_xss` | Fix terminal history-recall XSS (M-1) | audit finding M-1 |
|
|
| `02_simulate_fetch_commands` | Remove unvalidated client fetch from curl/wget (M-2) | audit finding M-2 |
|
|
| `03_nginx_security_headers` | Security headers on every location (M-4) + `server_tokens off` (L-2) | audit findings M-4, L-2 |
|
|
|
|
**Dismissed:** audit finding M-3 (README `0.0.0.0:8080` binding) — false
|
|
positive per project owner (2026-09-18); the host firewall already restricts
|
|
access and the site is fronted by the Caddy edge.
|
|
|
|
**Completed in-session (not phased):** code-quality pass 2026-09-18 — module
|
|
split (Q-1), dead-code removal (Q-2/3/4, `scrollOffset`), expand/collapse
|
|
helpers (Q-5), rack-decoration CSS classes (Q-7), `hidden`-attribute reveal
|
|
(Q-8), a11y label on terminal input (Q-9), dynamic `date` (Q-10), vim `dd`
|
|
line-deletion fix, Playwright regression suite (44 tests). See
|
|
`.agents/remediation_plan.md`.
|
|
|
|
Remaining low-priority audit items (not yet phased): L-1 (verify HSTS at the
|
|
Caddy edge — folded into Phase 03 verification), L-3 (drop
|
|
`style-src 'unsafe-inline'` after moving inline `style=""` attrs to classes),
|
|
L-5 (label the displayed SSH key as fictitious or show fingerprint only),
|
|
L-7 (pin CI action SHAs / image signing), L-8 (build.sh verification test in
|
|
CI).
|
|
|
|
## 8. Review History
|
|
|
|
- **2026-09-18** — Security & code-quality audit; module split and the
|
|
`@playwright/test` 1.62.0 / chromium-1234 pin approved.
|
|
- **2026-09-18** — User-approved dependency update: `@playwright/test`
|
|
bumped 1.62.0 → 1.63.0; §3 lock re-pinned to 1.63.0 (matches cached
|
|
chromium-1243, re-downloaded locally). Full 44-test E2E suite green on
|
|
1.63.0. Executed as a direct change per explicit user instruction
|
|
(no phase).
|