Skip to content

Update documentation for remote auth tokens and validation commands#42

Merged
tyl3r-ch merged 19 commits into
mainfrom
v632
May 5, 2026
Merged

Update documentation for remote auth tokens and validation commands#42
tyl3r-ch merged 19 commits into
mainfrom
v632

Conversation

@tyl3r-ch
Copy link
Copy Markdown
Contributor

@tyl3r-ch tyl3r-ch commented May 5, 2026

Summary by CodeRabbit

  • Documentation
    • Remote deployment now requires explicit opt‑in plus a long remote token and documents required headers, non‑loopback warnings, and safe proxying. README and CONTRIBUTING update CLI guidance and recommend the CI-style Playwright run on an alternate port (PLAYWRIGHT_TEST_PORT=3016).
  • Improvements
    • Screenshot flow now uses an authenticated, seeded runtime and waits for actual rendered chart data before capturing.
  • Tests
    • Added documentation contract tests and comprehensive unit/e2e tests for screenshot and chart readiness helpers.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2e3be7b3-1006-400c-9abb-e22859076894

📥 Commits

Reviewing files that changed from the base of the PR and between b11691a and 3d640f8.

📒 Files selected for processing (8)
  • README.md
  • SECURITY.md
  • scripts/capture-readme-screenshots.js
  • tests/e2e/dashboard-load-upload.spec.ts
  • tests/e2e/fixtures.ts
  • tests/unit/documentation-contract.test.ts
  • tests/unit/readme-screenshots-script.test.ts
  • tests/unit/rendered-chart-data.test.ts

📝 Walkthrough

Walkthrough

This PR updates docs to require a 24+ char remote token for non-loopback binds, standardizes Playwright CI test commands (port 3016 for CI-style runs), refactors and hardens the README screenshot script to use authenticated seeding and chart-readiness detection, adds chart-rendering helpers, and adds unit and e2e tests for docs, auth, seeding, and chart readiness.

Changes

Documentation, Authentication & Screenshot Infrastructure

Layer / File(s) Summary
Docs (policy + examples)
CONTRIBUTING.md, README.md, SECURITY.md
Require explicit opt-in + TTDASH_REMOTE_TOKEN (≥24 chars) for non-loopback binding; show example HOST=0.0.0.0 + TTDASH_ALLOW_REMOTE=1 + TTDASH_REMOTE_TOKEN; document Authorization: Bearer $TTDASH_REMOTE_TOKEN and X-TTDash-Remote-Token; prefer PLAYWRIGHT_TEST_PORT=3016 npm run test:e2e:ci; recommend exact pinned toktrack via bunx/npx --yes.
Screenshot runtime data shape & seeding
scripts/capture-readme-screenshots.js (seed helpers) , scripts/rendered-chart-data.js
Add deterministic auth/session shape (createScreenshotAuthSession, screenshotLocalAuthToken, screenshotSeedLoadedAt), atomic JSON write/read and seedSampleUsageFile to persist data.json/settings.json for the screenshot runtime.
Server readiness & polling
scripts/capture-readme-screenshots.js (wait logic)
Replace unauthenticated probe with waitForServer(url, { authSession,... }) that polls /api/usage with auth headers, uses AbortController, returns the reachable authSession, and normalizes timeout errors.
Chart rendering detection
scripts/rendered-chart-data.js
New renderedChartDataSelector, countRenderedChartDataShapes(section), and waitForRenderedChartData(page, options) that detect visible Recharts SVG shapes via visibility/opacity and geometry checks and provide timeout-normalized errors.
Screenshot capture wiring
scripts/capture-readme-screenshots.js (capture flow)
Start server with PLAYWRIGHT_TEST_RUNTIME_ROOT + TTDASH_LOCAL_AUTH_TOKEN, wait via waitForServer, call seedSampleUsageFile, navigate to `authSession.bootstrapUrl
E2E test updates & helpers
tests/e2e/dashboard-load-upload.spec.ts, tests/e2e/fixtures.ts
Add chartCardByTitle test helper; update dashboard load test to assert rendered chart shapes via countRenderedChartDataShapes instead of only static headings.
Unit tests (docs & scripts)
tests/unit/documentation-contract.test.ts, tests/unit/readme-screenshots-script.test.ts, tests/unit/rendered-chart-data.test.ts
New Vitest suites: documentation-contracts enforce token/README/CONTRIBUTING/Playwright command patterns; readme-screenshots tests cover auth/session, waitForServer polling/timeout/abort, seedSampleUsageFile validation/atomic write, closeBrowserResources behavior, stopServer escalation; rendered-chart-data tests verify polling, timeout normalization, and shared time-budget behavior.
Exports / API surface
scripts/capture-readme-screenshots.js, scripts/rendered-chart-data.js, tests/e2e/fixtures.ts
New CommonJS exports: createScreenshotAuthSession, createAuthHeaders, closeBrowserResources, isChildProcessRunning, stopServer, seedSampleUsageFile, waitForServer (returns authSession), screenshotLocalAuthToken, screenshotSeedLoadedAt; and exported renderedChartDataSelector, countRenderedChartDataShapes, waitForRenderedChartData; chartCardByTitle export added for tests.

Sequence Diagram(s)

sequenceDiagram
    participant Script as Screenshot Script
    participant Server as Test Server
    participant API as /api/usage
    participant Browser as Browser

    Script->>Server: start server with runtime root & local auth token
    Server-->>Script: exposes bootstrap URL & accepts auth token
    Script->>API: waitForServer(/api/usage) with Authorization header
    API-->>Script: returns OK (authSession reachable)
    Script->>Server: seedSampleUsageFile (writes data.json/settings.json)
    Server-->>Script: seed success
    Script->>Browser: launch & navigate to authSession.bootstrapUrl
    Browser->>Server: load dashboard (renders charts)
    Script->>Browser: waitForRenderedChartData -> countRenderedChartDataShapes polling
    Browser-->>Script: chart shapes >= minShapes
    Script->>Browser: capture screenshot
    Script->>Server: stopServer (SIGTERM, escalate to SIGKILL if needed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • roastcodes/ttdash#36: Overlaps Playwright port/CI command and CONTRIBUTING/README guidance changes.
  • roastcodes/ttdash#11: Earlier screenshot-capture script work; related to the refactor/export of scripts/capture-readme-screenshots.js.
  • roastcodes/ttdash#18: Related README toktrack pinning changes and charting/context updates.

Poem

🐰
I hop with a token, snug and neat,
seeding data, watching charts take seat.
Playwright hums on port three-oh-one-six,
screenshots captured, no flaky tricks.
A tidy repo—snap, blink, and repeat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes across the PR: documentation updates covering remote authentication tokens and validation command guidance (e.g., Playwright test ports, remote token requirements).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v632

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread scripts/capture-readme-screenshots.js Fixed
Comment thread scripts/capture-readme-screenshots.js Fixed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/capture-readme-screenshots.js (1)

146-185: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make browser and child-process teardown exception-safe.

If anything throws after chromium.launch(), neither the browser nor the context is guaranteed to close. Also, the current server.once('close') wait can hang if the child has already emitted close before the finally block runs. Move browser cleanup into a nested finally, and only await close when the child is still alive.

♻️ Cleanup shape to avoid leaked Chromium processes and stuck shutdowns
-  try {
+  let browser;
+  let context;
+  try {
     const authSession = await waitForServer(baseUrl);
     await seedSampleUsage({ authSession });

-    const browser = await chromium.launch();
-    const context = await browser.newContext({
+    browser = await chromium.launch();
+    context = await browser.newContext({
       viewport: { width: 1600, height: 1400 },
       colorScheme: 'dark',
       reducedMotion: 'reduce',
     });
-    const page = await context.newPage();
+    const page = await context.newPage();

     // ...
-
-    await context.close();
-    await browser.close();
   } finally {
-    server.kill('SIGTERM');
-    await new Promise((resolve) => server.once('close', resolve));
+    await context?.close().catch(() => {});
+    await browser?.close().catch(() => {});
+
+    if (server.exitCode === null && server.signalCode === null) {
+      const closed = new Promise((resolve) => server.once('close', resolve));
+      server.kill('SIGTERM');
+      await closed;
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/capture-readme-screenshots.js` around lines 146 - 185, The
try/finally currently can leak Chromium if an exception occurs before
context/browser are closed and can hang awaiting server.once('close') if the
child already closed; refactor so that after calling chromium.launch() you have
a nested try/finally that always attempts context.close() and browser.close()
(guarding for undefined browser/context) in its finally block, and in the outer
finally only call server.kill('SIGTERM') and await server.once('close')
conditionally (e.g., check server.killed or server.exitCode / an isAlive flag)
so you only await close when the child is still running; update code references
around chromium.launch(), context.close(), browser.close(),
server.kill('SIGTERM') and server.once('close') accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/capture-readme-screenshots.js`:
- Around line 66-79: The polling loop in waitForServer can exceed the intended
timeout because fetchImpl and sleepImpl may run past the remaining budget;
compute remainingTimeoutMs at the top of each iteration (using startedAt and
timeoutMs) and if <= 0 immediately throw, create an AbortController and pass its
signal to fetchImpl (and to any internal fetch timeout), start a timer to abort
the controller when remainingTimeoutMs elapses so in-flight fetches are
cancelled, and cap the sleepImpl duration to Math.min(pollMs,
remainingTimeoutMs) so you never sleep past the budget; use the existing symbols
readAuthStatusImpl, fetchImpl, createAuthHeaders, sleepImpl, authStatusFile and
the waitForServer loop to locate the changes.

In `@SECURITY.md`:
- Around line 38-40: Update the curl example in SECURITY.md to use a concrete
reachable host instead of the bind address 0.0.0.0; replace the request URL
shown in the snippet (the curl command that currently targets
http://0.0.0.0:3000/api/usage) with a concrete host such as
http://127.0.0.1:3000/api/usage for local examples or indicate using the
server's LAN/public IP for remote access so readers know to target a reachable
address.

In `@tests/unit/documentation-contract.test.ts`:
- Around line 22-25: The SECURITY.md contract test is missing an assertion for
the X-TTDash-Remote-Token header, so update the test in
tests/unit/documentation-contract.test.ts to also assert that
docs['SECURITY.md'] contains 'X-TTDash-Remote-Token' (similar to the existing
README.md checks); locate the test that references docs['README.md'] and
docs['SECURITY.md'] and add the additional expect(...) assertion for the
SECURITY.md content to ensure the header isn't accidentally removed.

---

Outside diff comments:
In `@scripts/capture-readme-screenshots.js`:
- Around line 146-185: The try/finally currently can leak Chromium if an
exception occurs before context/browser are closed and can hang awaiting
server.once('close') if the child already closed; refactor so that after calling
chromium.launch() you have a nested try/finally that always attempts
context.close() and browser.close() (guarding for undefined browser/context) in
its finally block, and in the outer finally only call server.kill('SIGTERM') and
await server.once('close') conditionally (e.g., check server.killed or
server.exitCode / an isAlive flag) so you only await close when the child is
still running; update code references around chromium.launch(), context.close(),
browser.close(), server.kill('SIGTERM') and server.once('close') accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e15cf00f-236b-43da-a412-97583917fab3

📥 Commits

Reviewing files that changed from the base of the PR and between 3d81684 and 9898d59.

⛔ Files ignored due to path filters (3)
  • docs/ttdash-dashboard-analytics.png is excluded by !**/*.png
  • docs/ttdash-dashboard-settings.png is excluded by !**/*.png
  • docs/ttdash-dashboard.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • CONTRIBUTING.md
  • README.md
  • SECURITY.md
  • scripts/capture-readme-screenshots.js
  • scripts/rendered-chart-data.js
  • tests/e2e/dashboard-load-upload.spec.ts
  • tests/unit/documentation-contract.test.ts
  • tests/unit/readme-screenshots-script.test.ts

Comment thread scripts/capture-readme-screenshots.js Outdated
Comment thread SECURITY.md
Comment thread tests/unit/documentation-contract.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/dashboard-load-upload.spec.ts (1)

62-74: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Scope the shape-count assertion to the two charts this test names.

countRenderedChartDataShapes(costAnalysisSection) will still pass if either “Cumulative cost per provider” or “Cost by model over time” stops rendering while any other chart inside #charts still draws enough SVG paths. Please assert rendered data under each chart container instead of the whole section.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/dashboard-load-upload.spec.ts` around lines 62 - 74, The assertion
currently calls countRenderedChartDataShapes(costAnalysisSection) for the whole
`#charts` section which can hide a failure of either "Cumulative cost per
provider" or "Cost by model over time"; instead locate each chart container via
costAnalysisSection.getByText(/Cumulative cost per provider|Kumulative Kosten
pro Anbieter/) and costAnalysisSection.getByText(/Cost by model over time|Kosten
nach Modell im Zeitverlauf/) (or their parent/chart wrapper), then call
countRenderedChartDataShapes() on each individual chart container and replace
the single poll assertion with two polls asserting each chart's shape count is >
0 (using the same expect.poll(...).toBeGreaterThan(...) pattern).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/capture-readme-screenshots.js`:
- Around line 221-235: The stopServer helper can hang waiting for 'close' if the
child ignores SIGTERM; update stopServer to add a shutdown deadline by wrapping
the existing promise with a timeout (use setTimeout) that will resolve if the
child hasn't closed within N ms, and on timeout attempt a stronger termination
(e.g., server.kill('SIGKILL')) and cleanup the 'close' listener and timeout.
Reference stopServer, isChildProcessRunning, server.kill, and the
server.once('close', ...) listener when making the changes so the promise always
resolves on success, error, or deadline and no listeners/timeouts are leaked.

In `@SECURITY.md`:
- Around line 38-43: Update the guidance that currently suggests substituting a
“public host name” for 127.0.0.1 when using the TTDASH_ALLOW_REMOTE,
TTDASH_REMOTE_TOKEN, HOST and ttdash example and the curl Authorization call:
explicitly restrict the example to LAN/VPN/SSH-tunneled access or require an
HTTPS reverse proxy/valid TLS termination before exposing the bearer token on
any public hostname, and mirror the same wording change in README.md to keep
both docs consistent.

In `@tests/unit/documentation-contract.test.ts`:
- Around line 14-20: The test's regression checks
(remoteBindWithoutTokenPattern, the expect on URL, and the TTDASH_REMOTE_TOKEN
assertion) are too narrow and miss permutations like different env-var order or
different ports; update the pattern and assertions to (1) use a regex that
detects TTDASH_ALLOW_REMOTE=1 and HOST=0.0.0.0 in any order without an
intervening TTDASH_REMOTE_TOKEN (e.g. look for both keys with a negative
lookahead for the token), (2) replace the exact URL check with a regex matching
http://0\.0\.0\.0(:\d+)?/api/usage so any port is caught, and (3) keep/assert
the TTDASH_REMOTE_TOKEN placeholder string
(TTDASH_REMOTE_TOKEN=<long-random-token>) still exists in docs entries; apply
these changes where the test iterates over docs and references
remoteBindWithoutTokenPattern, the URL expect, and the token expect.

In `@tests/unit/readme-screenshots-script.test.ts`:
- Around line 77-95: This test file mixes coverage for the chart-render helper
with the README screenshot script; extract all tests that exercise
renderedChartDataSelector and waitForRenderedChartData (the
require('../../scripts/rendered-chart-data.js') usage and any assertions around
those helpers) into a new focused unit test file (e.g.
tests/unit/rendered-chart-data.test.ts), update imports to
require('../../scripts/rendered-chart-data.js') and keep the existing typed
shape, and remove those chart-helper tests (lines exercising the helper, roughly
the block covering the helper behavior referenced in the review) from
tests/unit/readme-screenshots-script.test.ts so the README screenshot test only
covers capture-readme-screenshots.js.

---

Outside diff comments:
In `@tests/e2e/dashboard-load-upload.spec.ts`:
- Around line 62-74: The assertion currently calls
countRenderedChartDataShapes(costAnalysisSection) for the whole `#charts` section
which can hide a failure of either "Cumulative cost per provider" or "Cost by
model over time"; instead locate each chart container via
costAnalysisSection.getByText(/Cumulative cost per provider|Kumulative Kosten
pro Anbieter/) and costAnalysisSection.getByText(/Cost by model over time|Kosten
nach Modell im Zeitverlauf/) (or their parent/chart wrapper), then call
countRenderedChartDataShapes() on each individual chart container and replace
the single poll assertion with two polls asserting each chart's shape count is >
0 (using the same expect.poll(...).toBeGreaterThan(...) pattern).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 397b09ca-7032-4fb9-a208-091489866716

📥 Commits

Reviewing files that changed from the base of the PR and between 9898d59 and b11691a.

⛔ Files ignored due to path filters (1)
  • docs/ttdash-dashboard.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • README.md
  • SECURITY.md
  • scripts/capture-readme-screenshots.js
  • scripts/rendered-chart-data.js
  • tests/e2e/dashboard-load-upload.spec.ts
  • tests/unit/documentation-contract.test.ts
  • tests/unit/readme-screenshots-script.test.ts

Comment thread scripts/capture-readme-screenshots.js Outdated
Comment thread SECURITY.md Outdated
Comment thread tests/unit/documentation-contract.test.ts
Comment thread tests/unit/readme-screenshots-script.test.ts Outdated
@tyl3r-ch tyl3r-ch merged commit 3898251 into main May 5, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants