From 486f77557af6f63ab1cae5275c549b4397465ee1 Mon Sep 17 00:00:00 2001 From: Hoid Date: Wed, 25 Feb 2026 19:05:56 +0000 Subject: [PATCH] DocFast session 96: 130 tests, security util extraction --- memory/calendar-reminders-sent.json | 25 ++++++++++-- memory/portfolio.json | 14 +++---- memory/wind-down-log.json | 15 +++---- projects/business/memory/bugs.md | 9 +++++ projects/business/memory/sessions.md | 58 ++++++++++++++++++++++++++++ projects/business/memory/state.json | 4 +- projects/snapapi/memory/sessions.md | 27 +++++++++++++ projects/snapapi/memory/state.json | 9 +++-- 8 files changed, 135 insertions(+), 26 deletions(-) diff --git a/memory/calendar-reminders-sent.json b/memory/calendar-reminders-sent.json index 63e7efd..04fe98b 100644 --- a/memory/calendar-reminders-sent.json +++ b/memory/calendar-reminders-sent.json @@ -1,7 +1,24 @@ { "sent": [ - {"event": "Marie besuchen", "date": "2026-02-07", "remindedAt": "2026-02-07T09:31:00Z"}, - {"event": "StandUp Team", "date": "2026-02-24", "remindedAt": "2026-02-24T08:02:00Z"}, - {"event": "Friseur", "date": "2026-02-25", "remindedAt": "2026-02-25T08:08:00Z"} + { + "event": "Marie besuchen", + "date": "2026-02-07", + "remindedAt": "2026-02-07T09:31:00Z" + }, + { + "event": "StandUp Team", + "date": "2026-02-24", + "remindedAt": "2026-02-24T08:02:00Z" + }, + { + "event": "Friseur", + "date": "2026-02-25", + "remindedAt": "2026-02-25T08:08:00Z" + }, + { + "event": "Friseur", + "date": "2026-02-25", + "remindedAt": "2026-02-25T11:01:00Z" + } ] -} +} \ No newline at end of file diff --git a/memory/portfolio.json b/memory/portfolio.json index ddf2887..94d9a40 100644 --- a/memory/portfolio.json +++ b/memory/portfolio.json @@ -52,14 +52,14 @@ ], "notes": "N26 uses Xetra tickers. Always provide ISIN for orders. Fractional shares by EUR amount supported.", "created": "2026-02-12T20:00:00Z", - "lastUpdated": "2026-02-24T16:15:00Z", + "lastUpdated": "2026-02-25T16:15:00Z", "closingSnapshot": { - "date": "2026-02-24", - "DFNS": 59.25, - "portfolioValue": 1053.70, - "dailyPL": 5.69, - "dailyPLpct": 0.54, - "totalReturn": 5.37 + "date": "2026-02-25", + "DFNS": 58.96, + "portfolioValue": 1048.55, + "dailyPL": -5.16, + "dailyPLpct": -0.49, + "totalReturn": 4.85 }, "pendingActions": [] } diff --git a/memory/wind-down-log.json b/memory/wind-down-log.json index 90404e7..4d1d5a1 100644 --- a/memory/wind-down-log.json +++ b/memory/wind-down-log.json @@ -1,16 +1,11 @@ { - "date": "2026-02-24", + "date": "2026-02-25", "events": [ - {"time": "19:27", "activity": "Wind-down check-in sent. Suggested Askir audiobook + Kinder der Zeit. Reminded about Friseur tomorrow.", "source": "heartbeat"}, - {"time": "19:30", "activity": "Fixing one minor bug in workout app, then winding down. Plans to watch Detective Conan.", "source": "chat"}, - {"time": "20:27", "activity": "Follow-up check-in: asked if bug is done, nudged toward Conan.", "source": "heartbeat"}, - {"time": "21:30", "activity": "Nose shower done ✅. Watching Detective Conan.", "source": "chat"}, - {"time": "21:30", "activity": "FEEDBACK: Don't narrate internal reasoning in messages — just talk naturally.", "source": "chat"}, - {"time": "23:27", "activity": "No messages since ~21:30. Likely still watching Conan or heading to bed.", "source": "estimate"}, - {"time": "~23:45", "activity": "Going to sleep. Wants to implement better sync status visibility in workout app tomorrow.", "source": "chat"} + {"time": "19:09", "activity": "Wind-down check-in sent. Suggested Conan (Moonlight Sonata Murder Case) or King of Queens.", "source": "heartbeat"}, + {"time": "20:10", "activity": "Still working on something, finishing up. Plans to watch something after.", "source": "chat"} ], "yesterday": { - "sleep": "~midnight (estimated)", - "summary": "SSH tinkering, nose shower done, asleep ~midnight" + "sleep": "~23:45 (said going to sleep)", + "summary": "Bug fix in workout app, Detective Conan, nose shower done, asleep ~midnight" } } diff --git a/projects/business/memory/bugs.md b/projects/business/memory/bugs.md index f104ce7..ef1d751 100644 --- a/projects/business/memory/bugs.md +++ b/projects/business/memory/bugs.md @@ -1,3 +1,12 @@ +## BUG-087: OpenAPI spec empty on staging — swagger-jsdoc 7.0.0-rc.6 regression +- **Date:** 2026-02-25 +- **Severity:** HIGH +- **Issue:** Session 93 upgraded swagger-jsdoc from 6.2.8 to 7.0.0-rc.6 to fix a minimatch ReDoS vuln. The RC is broken — `swaggerJsdoc()` returns `{}` (empty object, 0 paths). The `/docs` page on staging shows no API endpoints. `/openapi.json` returns `{}`. +- **Root cause:** swagger-jsdoc 7.0.0-rc.6 does not parse `@openapi` JSDoc annotations from glob-matched files. +- **Impact:** Staging has no API documentation. Production (v0.4.5) is unaffected (still on 6.2.8 build). +- **Fix:** Reverted to swagger-jsdoc 6.2.8. Added 2 regression tests verifying OpenAPI spec has paths and includes key endpoints. npm audit still shows 0 vulnerabilities. +- **Status:** ✅ FIXED — commit 288d6c7, deploying to staging + ## BUG-080: Landing page still shows Free tier after v0.4.0 "removal" - **Date:** 2026-02-20 - **Severity:** HIGH diff --git a/projects/business/memory/sessions.md b/projects/business/memory/sessions.md index de78ee6..de5974f 100644 --- a/projects/business/memory/sessions.md +++ b/projects/business/memory/sessions.md @@ -1,5 +1,63 @@ # Session Log +## Session 96 — 2026-02-25 19:00 UTC (Wednesday Evening) +- **Production:** v0.4.5 ✅ healthy, 2 replicas, 0 restarts +- **Staging:** v0.5.1 ✅ healthy (new commit deploying) +- **K8s cluster:** All 3 nodes Ready +- **Support:** Zero tickets +- **Proactive improvements completed:** + 1. **Extracted and unit-tested security-critical utility functions:** + - `isPrivateIP` → `src/utils/network.ts` (19 tests: IPv4 private/public ranges, IPv6 loopback/link-local/unique-local, IPv4-mapped IPv6, edge cases) + - `isTransientError` → `src/utils/errors.ts` (23 tests: all PG error codes, message-based matches, null/undefined, non-transient errors) + - `escapeHtml` → `src/utils/html.ts` (9 tests: all special chars, empty string, double-escaping, mixed content) + - `markdownToHtml` / `wrapHtml` (12 tests: headings, bold, italic, links, code blocks, custom/default CSS, empty input) + 2. **Code quality:** Extracted inline functions to shared utils for testability and reuse. Original files import from new locations. Backward-compatible re-exports maintained. + 3. **130 tests total** (up from 67), all passing in ~4s across 7 test files. +- **Commit:** 50a163b pushed to main → auto-deploys to staging +- **Investor test:** All 5 checks pass ✅ +- **Budget:** €181.71 remaining, Revenue: €9 +- **Pending for investor:** + - Production tag for latest staging (20+ commits ahead of prod v0.4.5) + - SDK tokens (npm/PyPI/Go/Packagist) + - Google Search Console verification + +## Session 95 — 2026-02-25 16:00 UTC (Wednesday Late Afternoon) +- **Production:** v0.4.5 ✅ healthy, 2 replicas, 0 restarts +- **Staging:** v0.5.1 ✅ healthy, OpenAPI spec working (BUG-087 fix confirmed deployed) +- **K8s cluster:** All 3 nodes Ready +- **Support:** Zero tickets +- **Proactive improvements completed:** + 1. **Deduplicated `sanitizeFilename`** — extracted to shared `src/utils/sanitize.ts`, removed duplicate implementations from convert.ts and templates.ts. Consistent behavior: replace dangerous chars with _, trim, limit 200 chars, default fallback. + 2. **Fixed XSS vector in `esc()` function** — added single-quote escaping (`'` → `'`) in template rendering for attribute context safety. + 3. **New test files** — `src/__tests__/sanitize.test.ts` (6 tests) + `src/__tests__/templates.test.ts` (5 tests). Tests cover: filename sanitization edge cases, template rendering with correct totals, HTML entity escaping including XSS prevention, unknown template handling. + 4. **67 tests total** (up from 57), all passing in 2.3s across 3 test files. +- **Commit:** 0a002f9 pushed to main → auto-deploys to staging +- **Investor test:** All 5 checks pass ✅ +- **Budget:** €181.71 remaining, Revenue: €9 +- **Note:** claude-sonnet-4-512k sub-agents failing instantly (model unavailability?). Used Opus for dev work. +- **Pending for investor:** + - Production tag for latest staging (20+ commits ahead of prod v0.4.5) + - SDK tokens (npm/PyPI/Go/Packagist) + - Google Search Console verification + +## Session 94 — 2026-02-25 13:00 UTC (Wednesday Afternoon) +- **Production:** v0.4.5 ✅ healthy, 75k+ seconds uptime, 2 replicas, 0 restarts +- **Staging:** v0.5.1 ✅ healthy (but pending redeploy with new commits) +- **K8s cluster:** All 3 nodes Ready +- **Support:** Zero tickets +- **Proactive improvements completed:** + 1. **BUG-087 FOUND & FIXED** — swagger-jsdoc 7.0.0-rc.6 (upgraded in session 93) broke OpenAPI spec generation. `/openapi.json` returns `{}` on staging. Reverted to 6.2.8 (0 vulns). Added 2 regression tests. Commit 288d6c7. + 2. **Unhandled error handlers** — Added `process.on('uncaughtException')` and `process.on('unhandledRejection')` with fatal logging + exit. Previously a stray rejection could crash silently. Commit c4fea79. + 3. **New tests** — SSRF blocks 0.0.0.0, Content-Disposition default/custom filename, OpenAPI spec validation. **56 tests total** (up from 52). +- **CI issue:** ARM64 cross-compile builds appear stuck/slow. Commits 288d6c7 and c4fea79 pushed but staging hasn't redeployed yet after 10+ minutes. May need CI runner check. +- **Investor test:** All 5 checks pass ✅ (production unaffected by staging regression) +- **Budget:** €181.71 remaining, Revenue: €9 +- **Pending for investor:** + - CI runner may need restart (builds not deploying) + - Production tag for latest staging (20+ commits ahead of prod v0.4.5) + - SDK tokens (npm/PyPI/Go/Packagist) + - Google Search Console verification + ## Session 93 — 2026-02-25 10:00 UTC (Wednesday Mid-Morning) - **Production:** v0.4.5 ✅ healthy, 64k+ seconds uptime, 2 replicas, 0 restarts - **Staging:** v0.5.1 ✅ healthy, pod running on w1 diff --git a/projects/business/memory/state.json b/projects/business/memory/state.json index 75551f4..f344da0 100644 --- a/projects/business/memory/state.json +++ b/projects/business/memory/state.json @@ -3,7 +3,7 @@ "phaseLabel": "Build Production-Grade Product", "status": "launch-ready", "product": "DocFast — HTML/Markdown to PDF API", - "currentPriority": "Staging ready for prod tag (18 commits ahead). Still need SDK tokens + GSC verification. Test suite: 52 tests passing, 0 npm vulnerabilities.", + "currentPriority": "Staging ready for prod tag (20+ commits ahead). Test suite: 130 tests passing (7 test files), 0 npm vulnerabilities. Still need SDK tokens + GSC verification.", "ownerDirectives_PRIORITY": "Process these IN ORDER. Do not skip. Remove items marked ✅ DONE/FIXED during housekeeping.", "ownerDirectives": [ "Stripe Product ID for DocFast: prod_TygeG8tQPtEAdE — webhook handler must filter by this product_id to ignore events from other projects on the same Stripe account." @@ -85,5 +85,5 @@ }, "blockers": [], "startDate": "2026-02-14", - "sessionCount": 93 + "sessionCount": 96 } diff --git a/projects/snapapi/memory/sessions.md b/projects/snapapi/memory/sessions.md index 7f29e2a..2b3bfa6 100644 --- a/projects/snapapi/memory/sessions.md +++ b/projects/snapapi/memory/sessions.md @@ -1,5 +1,32 @@ # SnapAPI Session Log +## Session 24 — 2026-02-25 14:00 UTC (Usage Dashboard Feature) + +**Goal:** Build customer-facing usage dashboard — a real gap where customers had no way to check their API usage. + +**Built:** +- `GET /v1/usage` API endpoint — authenticated, returns used/limit/plan/month/remaining/percentUsed +- `usage.html` page — dark-themed, input API key, visual progress bar, warning (>80%) and danger (>95%) states +- 4 new tests (TDD: failing first → implementation → green) +- Updated landing page nav + footer with "Check Usage" links +- OpenAPI/Swagger docs updated + +**Results:** +- Tests: 133 passing (up from 129), all green +- Code pushed to main, deployed to staging +- Commit: 5b59a7a + +**Investor Test:** +1. Trust with money? Mostly — checkout works, Stripe webhook unregistered +2. Data loss on crash? No — PostgreSQL +3. Free tier abuse? Low risk — IP-limited, watermarked, URL length capped +4. Key recovery? Yes on staging +5. Website features? All working + +**Still blocked:** Stripe webhook registration, CI/CD (Forgejo runner), staging TLS (DNS), production deploy (needs approval) + +--- + ## Session 23 — 2026-02-25 11:00 UTC (Health Check + Production Deploy Request) **Goal:** Verify system health, run investor test, request production deployment. diff --git a/projects/snapapi/memory/state.json b/projects/snapapi/memory/state.json index ed574a3..5509807 100644 --- a/projects/snapapi/memory/state.json +++ b/projects/snapapi/memory/state.json @@ -1,6 +1,6 @@ { "phase": "production-live", - "version": "0.4.3-prod / 0.5.1-staging", + "version": "0.4.3-prod / 0.5.2-staging", "staging": { "status": "running", "namespace": "snapapi-staging", @@ -57,7 +57,10 @@ "Stripe Customer Portal endpoint (POST /v1/billing/portal) — subscription management + key recovery (staging)", "API Key Recovery endpoint (GET /v1/billing/recover) — secure masked key lookup (staging)", "Recovery page at /recovery.html — user-facing key recovery form (staging)", - "Test suite: 129 tests passing (vitest) — SSRF, cache, auth, keys, billing, playground, screenshot, health, watermark", + "Usage Dashboard: GET /v1/usage API endpoint — returns used/limit/plan/month/remaining/percentUsed (staging)", + "Usage page at /usage.html — dark-themed dashboard with progress bar, warning/danger states (staging)", + "Usage Dashboard linked from landing page nav + footer (staging)", + "Test suite: 133 tests passing (vitest) — SSRF, cache, auth, keys, billing, playground, screenshot, health, watermark, usage", "Git deploy key configured on k3s-mgr for staging builds" ], "notDone": [ @@ -81,6 +84,6 @@ "priceId": "price_1T2XHpRtlDv9c8GoThHfd8kS" } }, - "lastSession": "2026-02-25T11:00:00Z", + "lastSession": "2026-02-25T14:00:00Z", "codeLocation": "Forgejo repo openclawd/SnapAPI. Clone: git clone forgejo-snapapi:openclawd/SnapAPI.git" }