DocFast session 96: 130 tests, security util extraction
This commit is contained in:
parent
052bf8519f
commit
486f77557a
8 changed files with 135 additions and 26 deletions
|
|
@ -1,7 +1,24 @@
|
||||||
{
|
{
|
||||||
"sent": [
|
"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": "Marie besuchen",
|
||||||
{"event": "Friseur", "date": "2026-02-25", "remindedAt": "2026-02-25T08:08:00Z"}
|
"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"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -52,14 +52,14 @@
|
||||||
],
|
],
|
||||||
"notes": "N26 uses Xetra tickers. Always provide ISIN for orders. Fractional shares by EUR amount supported.",
|
"notes": "N26 uses Xetra tickers. Always provide ISIN for orders. Fractional shares by EUR amount supported.",
|
||||||
"created": "2026-02-12T20:00:00Z",
|
"created": "2026-02-12T20:00:00Z",
|
||||||
"lastUpdated": "2026-02-24T16:15:00Z",
|
"lastUpdated": "2026-02-25T16:15:00Z",
|
||||||
"closingSnapshot": {
|
"closingSnapshot": {
|
||||||
"date": "2026-02-24",
|
"date": "2026-02-25",
|
||||||
"DFNS": 59.25,
|
"DFNS": 58.96,
|
||||||
"portfolioValue": 1053.70,
|
"portfolioValue": 1048.55,
|
||||||
"dailyPL": 5.69,
|
"dailyPL": -5.16,
|
||||||
"dailyPLpct": 0.54,
|
"dailyPLpct": -0.49,
|
||||||
"totalReturn": 5.37
|
"totalReturn": 4.85
|
||||||
},
|
},
|
||||||
"pendingActions": []
|
"pendingActions": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
{
|
{
|
||||||
"date": "2026-02-24",
|
"date": "2026-02-25",
|
||||||
"events": [
|
"events": [
|
||||||
{"time": "19:27", "activity": "Wind-down check-in sent. Suggested Askir audiobook + Kinder der Zeit. Reminded about Friseur tomorrow.", "source": "heartbeat"},
|
{"time": "19:09", "activity": "Wind-down check-in sent. Suggested Conan (Moonlight Sonata Murder Case) or King of Queens.", "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:10", "activity": "Still working on something, finishing up. Plans to watch something after.", "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"}
|
|
||||||
],
|
],
|
||||||
"yesterday": {
|
"yesterday": {
|
||||||
"sleep": "~midnight (estimated)",
|
"sleep": "~23:45 (said going to sleep)",
|
||||||
"summary": "SSH tinkering, nose shower done, asleep ~midnight"
|
"summary": "Bug fix in workout app, Detective Conan, nose shower done, asleep ~midnight"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
## BUG-080: Landing page still shows Free tier after v0.4.0 "removal"
|
||||||
- **Date:** 2026-02-20
|
- **Date:** 2026-02-20
|
||||||
- **Severity:** HIGH
|
- **Severity:** HIGH
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,63 @@
|
||||||
# Session Log
|
# 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)
|
## Session 93 — 2026-02-25 10:00 UTC (Wednesday Mid-Morning)
|
||||||
- **Production:** v0.4.5 ✅ healthy, 64k+ seconds uptime, 2 replicas, 0 restarts
|
- **Production:** v0.4.5 ✅ healthy, 64k+ seconds uptime, 2 replicas, 0 restarts
|
||||||
- **Staging:** v0.5.1 ✅ healthy, pod running on w1
|
- **Staging:** v0.5.1 ✅ healthy, pod running on w1
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"phaseLabel": "Build Production-Grade Product",
|
"phaseLabel": "Build Production-Grade Product",
|
||||||
"status": "launch-ready",
|
"status": "launch-ready",
|
||||||
"product": "DocFast — HTML/Markdown to PDF API",
|
"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_PRIORITY": "Process these IN ORDER. Do not skip. Remove items marked ✅ DONE/FIXED during housekeeping.",
|
||||||
"ownerDirectives": [
|
"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."
|
"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": [],
|
"blockers": [],
|
||||||
"startDate": "2026-02-14",
|
"startDate": "2026-02-14",
|
||||||
"sessionCount": 93
|
"sessionCount": 96
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,32 @@
|
||||||
# SnapAPI Session Log
|
# 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)
|
## Session 23 — 2026-02-25 11:00 UTC (Health Check + Production Deploy Request)
|
||||||
|
|
||||||
**Goal:** Verify system health, run investor test, request production deployment.
|
**Goal:** Verify system health, run investor test, request production deployment.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"phase": "production-live",
|
"phase": "production-live",
|
||||||
"version": "0.4.3-prod / 0.5.1-staging",
|
"version": "0.4.3-prod / 0.5.2-staging",
|
||||||
"staging": {
|
"staging": {
|
||||||
"status": "running",
|
"status": "running",
|
||||||
"namespace": "snapapi-staging",
|
"namespace": "snapapi-staging",
|
||||||
|
|
@ -57,7 +57,10 @@
|
||||||
"Stripe Customer Portal endpoint (POST /v1/billing/portal) — subscription management + key recovery (staging)",
|
"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)",
|
"API Key Recovery endpoint (GET /v1/billing/recover) — secure masked key lookup (staging)",
|
||||||
"Recovery page at /recovery.html — user-facing key recovery form (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"
|
"Git deploy key configured on k3s-mgr for staging builds"
|
||||||
],
|
],
|
||||||
"notDone": [
|
"notDone": [
|
||||||
|
|
@ -81,6 +84,6 @@
|
||||||
"priceId": "price_1T2XHpRtlDv9c8GoThHfd8kS"
|
"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"
|
"codeLocation": "Forgejo repo openclawd/SnapAPI. Clone: git clone forgejo-snapapi:openclawd/SnapAPI.git"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue