Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
59c70ad
Address PR 2567 review follow-ups
rmusser01 Jul 1, 2026
0d944fd
Update TASK-12088 with PR link
rmusser01 Jul 1, 2026
a5d2ab4
Address current main CodeQL alerts
rmusser01 Jul 1, 2026
c682782
Address PR 2568 review comments
rmusser01 Jul 2, 2026
3049553
Merge pull request #2568 from rmusser01/codex/pr-2567-review-followups
rmusser01 Jul 2, 2026
edc89a2
Prepare 0.1.34 release metadata
rmusser01 Jul 2, 2026
49e3abe
Merge pull request #2570 from rmusser01/codex/release-prep-current-dev
rmusser01 Jul 2, 2026
bd1639b
Fix WebUI llama.cpp auth and character avatars
rmusser01 Jul 2, 2026
a121537
Record PR link for WebUI llama.cpp fixes
rmusser01 Jul 2, 2026
b9f8341
Fix chat rail restore spacing
rmusser01 Jul 2, 2026
437c966
Fix chat rails and character speaker sync
rmusser01 Jul 2, 2026
69666ae
Refine chat cockpit mobile layout
rmusser01 Jul 2, 2026
0f68e64
Merge chat status into composer
rmusser01 Jul 2, 2026
61a02f0
Remove redundant chat sidebar edge rail
rmusser01 Jul 2, 2026
2a6f67c
Address chat cockpit PR review feedback
rmusser01 Jul 2, 2026
afb2660
Reset character chat on tracked character switch
rmusser01 Jul 2, 2026
6ef08f9
Add character greeting select action
rmusser01 Jul 2, 2026
2ab45ff
Address PR review avatar feedback
rmusser01 Jul 2, 2026
d49ce63
fix(webui): refresh chat state for character routes
rmusser01 Jul 2, 2026
782fac9
Fix character chat route switch regressions
rmusser01 Jul 2, 2026
8abd4f0
Fix remaining chat warning regressions
rmusser01 Jul 2, 2026
00d6e86
Address PR review placeholder auth issues
rmusser01 Jul 2, 2026
0b813d4
Address remaining PR review threads
rmusser01 Jul 2, 2026
8ce8a8b
Merge pull request #2573 from rmusser01/codex/llamacpp-webui-auth-avatar
rmusser01 Jul 2, 2026
661b76c
fix(frontend): remediate frontend + extension audit findings
rmusser01 Jul 2, 2026
c6e5a20
fix(frontend): remediate character-chat + TTS/STT audit (round 2, bat…
rmusser01 Jul 2, 2026
8eebdfb
fix(frontend): character-chat + TTS/STT audit follow-ups (round 2, ba…
rmusser01 Jul 2, 2026
a40c829
fix(frontend): keep chat context rail clear of app nav
rmusser01 Jul 2, 2026
4755c56
fix(frontend): address PR #2575 review comments
rmusser01 Jul 3, 2026
e101f19
Merge pull request #2575 from rmusser01/feat/frontend-extension-audit…
rmusser01 Jul 3, 2026
79ea6a0
Update apps/packages/ui/src/components/Option/Playground/__tests__/Pl…
rmusser01 Jul 3, 2026
a0e6cb4
Merge pull request #2576 from rmusser01/codex/chat-context-rail-nav-o…
rmusser01 Jul 3, 2026
bc3f8b6
docs: design standalone mcp document corpus
rmusser01 Jun 30, 2026
60b3271
docs: tighten standalone mcp docs corpus design
rmusser01 Jun 30, 2026
5f88050
docs: make mcp docs web acquisition optional
rmusser01 Jun 30, 2026
9c8d062
docs: plan standalone mcp docs stage 1
rmusser01 Jun 30, 2026
f8e0cfb
feat: add standalone docs package boundary
rmusser01 Jun 30, 2026
438c699
feat: add docs sqlite corpus store
rmusser01 Jun 30, 2026
4237acf
feat: add docs local import service
rmusser01 Jun 30, 2026
072b66e
feat: add docs retrieval context services
rmusser01 Jun 30, 2026
8ea4568
feat: add docs mcp tool provider
rmusser01 Jun 30, 2026
813e761
feat: register docs corpus mcp module
rmusser01 Jun 30, 2026
1aabc6d
chore: close docs corpus backlog task
rmusser01 Jun 30, 2026
76b2c39
docs: design mcp docs url acquisition
rmusser01 Jul 1, 2026
f3b9acf
docs: harden mcp docs url acquisition design
rmusser01 Jul 1, 2026
3da5ee5
docs: plan mcp docs url acquisition
rmusser01 Jul 1, 2026
ca47ce2
feat: add docs url acquisition settings
rmusser01 Jul 1, 2026
e5257f7
fix: harden docs url settings validation
rmusser01 Jul 1, 2026
8199887
feat: add docs url source policy
rmusser01 Jul 1, 2026
00d0add
fix: redact docs url policy matched rules
rmusser01 Jul 1, 2026
3f1b3c2
fix: harden docs url source policy
rmusser01 Jul 1, 2026
e23fea0
fix: deny legacy local hosts in docs policy
rmusser01 Jul 1, 2026
88d00a7
fix: fail closed on legacy numeric hosts
rmusser01 Jul 1, 2026
a52d7b2
fix: reject ambiguous docs policy hosts
rmusser01 Jul 1, 2026
f0d7095
fix: fail closed on ambiguous policy urls
rmusser01 Jul 1, 2026
4ea56bc
feat: add docs url fetcher
rmusser01 Jul 1, 2026
d811dba
feat: add lazy docs url extraction
rmusser01 Jul 1, 2026
bfb299a
feat: add docs url acquisition service
rmusser01 Jul 1, 2026
a011aa7
feat: expose docs url ingestion tool
rmusser01 Jul 1, 2026
b78a2f7
test: harden docs url acquisition boundaries
rmusser01 Jul 1, 2026
4a8b03b
chore: close docs url acquisition task
rmusser01 Jul 1, 2026
1b7d5ee
docs: plan MCP docs server mounting
rmusser01 Jul 1, 2026
634fd1b
feat: add standalone docs mount
rmusser01 Jul 1, 2026
d32a356
refactor: add docs host adapter boundary
rmusser01 Jul 1, 2026
6fe8dde
test: guard docs module server registration
rmusser01 Jul 1, 2026
af98a1c
test: enforce docs standalone mount boundaries
rmusser01 Jul 1, 2026
86db499
style: format docs server mounting tests
rmusser01 Jul 1, 2026
e682a3d
chore: close docs server mounting task
rmusser01 Jul 1, 2026
041ba59
fix: align docs package with standalone mcp source tree
rmusser01 Jul 1, 2026
ebf2e1b
fix: address standalone mcp docs review feedback
rmusser01 Jul 1, 2026
de99974
fix: address pr 2565 ci failures after rebase
rmusser01 Jul 1, 2026
6eb3330
Merge pull request #2565 from rmusser01/codex/mcp-docs-stage1
rmusser01 Jul 3, 2026
c62e5ad
fix(frontend): make chat focus mode fullscreen
rmusser01 Jul 3, 2026
259654b
chore: close workspace assistant defaults task
rmusser01 Jun 8, 2026
ec51c45
feat: map workspace assistant defaults in web client
rmusser01 Jun 8, 2026
1148b99
feat: expose workspace assistant default state
rmusser01 Jun 8, 2026
77b8872
feat: add workspace default assistant settings UI
rmusser01 Jun 8, 2026
77a9ddb
feat: apply workspace persona default to chat workspace
rmusser01 Jun 8, 2026
8d91b43
docs: close out workspace assistant defaults v1
rmusser01 Jun 8, 2026
83ae702
fix: address workspace assistant defaults review
rmusser01 Jun 9, 2026
a8515e3
fix: address workspace assistant defaults review follow-ups
rmusser01 Jul 1, 2026
8083f3f
ci: shard workspace assistant defaults api tests
rmusser01 Jul 1, 2026
2f0212b
fix: address workspace assistant defaults cubic review
rmusser01 Jul 1, 2026
763c4e7
fix(frontend): address chat focus review feedback
rmusser01 Jul 3, 2026
30c8460
Merge pull request #2578 from rmusser01/codex/chat-focus-fullscreen
rmusser01 Jul 3, 2026
0ee4797
Fix Knowledge QA auth for WebUI smoke
rmusser01 Jul 3, 2026
53383a0
Track PR 2316 rebase remediation
rmusser01 Jul 3, 2026
4ad2090
Merge pull request #2316 from rmusser01/codex/workspace-assistant-def…
rmusser01 Jul 3, 2026
09305d2
Address PR 2571 review comments
rmusser01 Jul 3, 2026
6f6dc16
docs(audits): add testing implementation audit (2026-07-02)
rmusser01 Jul 3, 2026
52edb51
ci(coverage): raise global floor 5->12, add AuthNZ scoped gate (audit…
rmusser01 Jul 3, 2026
43ab4be
test: replace norecursedirs hiding with visible quarantine skip (audi…
rmusser01 Jul 3, 2026
ad64617
fix(test): scope quarantine skip to own directory, not session-wide
rmusser01 Jul 3, 2026
7d20323
test(storage): cover folder create, file patch/delete, trash mutation…
rmusser01 Jul 3, 2026
c0f7c44
test: error-path sweep (401/422) across top-10 endpoints (audit F6)
rmusser01 Jul 3, 2026
f094603
fix(test): drop env-dependent audio routes from error-path sweep
rmusser01 Jul 3, 2026
4423521
test(rate-limiting): dedicated suite asserting 429 + Retry-After fire…
rmusser01 Jul 3, 2026
e103eb6
test(evals): fake clock for circuit-breaker waits; shrink 10s sleep t…
rmusser01 Jul 3, 2026
b5bdb0e
test: require reason= on unconditional skips (audit F9)
rmusser01 Jul 3, 2026
632c99b
fix(test): exclude skip-reason meta-test from its own scan; correct a…
rmusser01 Jul 3, 2026
c6868b6
test: hypothesis fuzzing for sanitize_filename and chunk_text (audit …
rmusser01 Jul 3, 2026
781734a
fix(test): derive chunker fuzz expectations from real sanitizer
rmusser01 Jul 3, 2026
0e562a8
ci(frontend): wire vitest v8 coverage + report-only CI summary (audit…
rmusser01 Jul 3, 2026
1e3ec3d
ci(perf): nightly non-gating performance run with artifact (audit F8)
rmusser01 Jul 3, 2026
5f237f0
fix(ci): set PERF=1 so nightly perf workflow actually runs the tests
rmusser01 Jul 3, 2026
416b4cc
fix(ci-local): load pytest_asyncio plugin like the CI workflows do
rmusser01 Jul 3, 2026
d12924b
fix(ci): preserve gating shard behavior for quarantined suites; shard…
rmusser01 Jul 3, 2026
7e7af03
test: cleanup pass from review minors (shared quarantine helper, iner…
rmusser01 Jul 3, 2026
39a2490
fix(test): stop pytestmark reassignment from dropping conditional ski…
rmusser01 Jul 3, 2026
e2bd39e
review: address PR #2579 bot findings
rmusser01 Jul 3, 2026
954acb1
chore: rerun PR 2571 CI
rmusser01 Jul 3, 2026
a01cbbf
Merge pull request #2579 from rmusser01/feat/testing-audit-remediation
rmusser01 Jul 3, 2026
473fa2c
Fix PR 2571 release CI guards
rmusser01 Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,43 @@ and this project adheres to Some kind of Versioning
### Removed


## [0.1.34] - 2026-07-02

> Rollup coverage: this entry covers current `dev` work that landed after the
> `0.1.33` release-prep metadata through PR #2568, including the post-PR #2567
> review follow-ups and current-main CodeQL alert cleanup.

### Added

- **PR 2568 Follow-Up Coverage** — Added Backlog records and focused
regression coverage for Jobs event-filter SQL helpers, public metrics-label
hashing, frontend auth persistence, and the `mcp-unified` PEP 561
`py.typed` marker/package-data contract.

### Changed

- **Jobs, WebSearch, And Auth Persistence Cleanup** — Moved Jobs event-filter
SQL construction behind DB management helpers, replaced WebSearch diagnostic
`print()` calls with structured Loguru logging, clarified Google parser debug
formatting, and restored browser persistence for manually entered API keys
and bearer tokens while preserving environment-provided auth precedence.
- **CodeQL Suppression Hygiene** — Updated validated path/auth/download/sync
suppressions from legacy LGTM comments to scoped CodeQL annotations with
local rationale on the reviewed paths.

### Fixed

- **PR 2567/2568 Review Follow-Ups** — Addressed review findings for DB-layer
ownership, missing helper/class docstrings, pytest unit markers, metrics tests
using public label normalization, WebSearch logging ambiguity, frontend auth
reload behavior, and the `mcp-unified` typed-marker package-data mismatch.

### Removed

- Removed stray WebSearch parser diagnostic `print()` calls from the current
release line.


## [0.1.33] - 2026-07-01

> Rollup coverage: this entry covers work that landed after the `0.1.32`
Expand Down
4 changes: 2 additions & 2 deletions Docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ markdown_extensions:

extra:
generator: false
version: v0.1.33
version: v0.1.34
social:
- icon: fontawesome/brands/github
link: https://github.com/rmusser01/tldw_server
name: GitHub
copyright: |
© 2024-2025 tldw_Server - v0.1.33 - <a href="https://github.com/rmusser01/tldw_server">GitHub</a>
© 2024-2025 tldw_Server - v0.1.34 - <a href="https://github.com/rmusser01/tldw_server">GitHub</a>

nav:
- Home: User_Guides/index.md
Expand Down
32 changes: 22 additions & 10 deletions Helper_Scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,16 +290,6 @@ def update_readme_release_references(readme_text: str, version: str) -> str:
rf"\g<1>{version}\g<2>",
"current release line",
),
(
rf"(?m)^(- The `dev` branch currently contains additional unreleased work beyond `){_SEMVER_PATTERN}(`; see \[CHANGELOG\.md\]\(CHANGELOG\.md\) for branch-level detail and \[Docs/Published/RELEASE_NOTES\.md\]\(Docs/Published/RELEASE_NOTES\.md\) for the published release entry point\.)$",
rf"\g<1>{version}\g<2>",
"beyond-release reference",
),
(
rf"(?m)^(Currently landing on `dev` \(post-`){_SEMVER_PATTERN}(` branch work\):)$",
rf"\g<1>{version}\g<2>",
"post-release reference",
),
]

updated_text = readme_text
Expand All @@ -308,6 +298,28 @@ def update_readme_release_references(readme_text: str, version: str) -> str:
if count == 0:
raise ValueError(f"Missing README anchor for {anchor_name}")

branch_line_pattern = rf"(?m)^- The `dev` branch .*beyond `{_SEMVER_PATTERN}`.*$"

def _replace_branch_line(match: re.Match[str]) -> str:
return re.sub(_SEMVER_PATTERN, version, match.group(0))

updated_text, count = re.subn(
branch_line_pattern,
_replace_branch_line,
updated_text,
count=1,
)
if count == 0:
raise ValueError("Missing README anchor for beyond-release reference")

updated_text, post_count = re.subn(
rf"(?m)^(Currently landing on `dev` \(post-`){_SEMVER_PATTERN}(` branch work\):)$",
rf"\g<1>{version}\g<2>",
updated_text,
)
if post_count == 0 and f"post-`{version}` branch work" not in updated_text:
raise ValueError("Missing README anchor for post-release reference")
Comment thread
rmusser01 marked this conversation as resolved.
Outdated

return updated_text


Expand Down
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ Optional add-ons (apply AFTER your base profile is healthy):
## Current Status

Current release line:
- `0.1.33` Beta status. Expect rough edges and please report issues.
- `0.1.34` Beta status. Expect rough edges and please report issues.
- Primary client surfaces are the Next.js WebUI, Admin UI, and browser extension.
- Package metadata is prepared under the canonical PyPI name `tldw-server`; use a repository checkout until publishing is complete.
- The `dev` branch carries work beyond `0.1.33`, including post-`0.1.33` branch work, and is prepared for the `0.1.33` release merge to `main`; see [CHANGELOG.md](CHANGELOG.md) for the PR rollup and [Docs/Published/RELEASE_NOTES.md](Docs/Published/RELEASE_NOTES.md) for the published release entry point.
- The `dev` branch carries work beyond `0.1.34`, including post-`0.1.34` branch work, and is prepared for the `0.1.34` release merge to `main`; see [CHANGELOG.md](CHANGELOG.md) for the PR rollup and [Docs/Published/RELEASE_NOTES.md](Docs/Published/RELEASE_NOTES.md) for the published release entry point.

<details>
<summary>Current focus and migration notes from the old Gradio version</summary>
Expand Down Expand Up @@ -146,18 +146,17 @@ Current release line:
## What's New (in the last few releases)

<details>
<summary>0.1.33 release-prep rollup</summary>
<summary>0.1.34 release-prep rollup</summary>

Included in the `0.1.33` release-prep rollup:
- Post-`0.1.32` dev/main stabilization for PR #1982 and PR #2557, including full-suite shard coverage mapping, MkDocs deploy verification, grouped CI fixes, and circuit-breaker flake cleanup.
- Fish Audio S2 TTS support, including provider registration, native backend/adapter wiring, voice metadata resolution, managed reference imports, contract fixes, and setup documentation.
- Explainer Workspace persistence, expansion jobs, grounding snapshots, chatbook export/import, UI surfaces, verification coverage, and follow-up hardening.
- MCP, Skills, and package-gateway readiness work covering runtime metadata, recovery/readiness fields, risky-module opt-in handling, standalone profile discovery, and residual UX review fixes.
- Chunking and moderation internals refactored around shared helpers and compiler abstractions while preserving existing parsing, dispatch, metrics, and service behavior.
- Release documentation and packaging cleanup for README skimming, root implementation-plan cleanup, MCP package-path clarity, VCS/manual backend extras, and stale release-branch artifacts.
Included in the `0.1.34` release-prep rollup:
- Post-`0.1.33` dev follow-ups for PR #2568, covering review feedback from the dev-to-main PR #2567 path and current-main CodeQL alert cleanup.
- Jobs event-filter SQL construction moved behind DB management helpers, with focused regression coverage for backend/column validation.
- WebSearch diagnostic logging cleaned up by replacing `print()` calls with structured Loguru logging and clearer Google raw-result debug formatting.
- Frontend auth persistence restored for manually entered API keys and bearer tokens while preserving environment-provided auth precedence.
- `mcp-unified` typed-marker/package-data coverage restored, and related package-boundary tests kept aligned with release metadata.

Still active on `dev`:
- Final CI for PR #2557 must clear before the prepared `0.1.33` release metadata is merged.
- Final CI for the prepared `0.1.34` release metadata must clear before this release is merged toward `main`.
- Treat [CHANGELOG.md](CHANGELOG.md) as the authoritative branch-level history for what has entered the release train.

See [CHANGELOG.md](CHANGELOG.md) for the full running history and [Docs/Published/RELEASE_NOTES.md](Docs/Published/RELEASE_NOTES.md) for published release notes.
Expand Down
1 change: 1 addition & 0 deletions apps/mcp-unified/src/mcp_unified/py.typed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

4 changes: 2 additions & 2 deletions apps/tldw-frontend/e2e/smoke/chat-openui-dynamic-ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
window.localStorage.setItem("assistant_setup_dismissed", "true")
window.localStorage.setItem("__tldw_first_run_complete", "true")
window.localStorage.setItem("__tldw_test_bypass", "true")
window.localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
window.localStorage.setItem("apiKey", authConfig.apiKey) // lgtm[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key
window.localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
window.localStorage.setItem("apiKey", authConfig.apiKey) // codeql[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
window.localStorage.setItem("authMode", authConfig.authMode)
})
}
Expand Down
4 changes: 2 additions & 2 deletions apps/tldw-frontend/e2e/smoke/chat-sticky-composer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
window.localStorage.setItem('assistant_setup_dismissed', 'true');
window.localStorage.setItem('__tldw_first_run_complete', 'true');
window.localStorage.setItem('__tldw_test_bypass', 'true');
window.localStorage.setItem('tldwConfig', JSON.stringify(authConfig)); // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
window.localStorage.setItem('apiKey', authConfig.apiKey); // lgtm[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key
window.localStorage.setItem('tldwConfig', JSON.stringify(authConfig)); // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
window.localStorage.setItem('apiKey', authConfig.apiKey); // codeql[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
window.localStorage.setItem('authMode', authConfig.authMode);
window.localStorage.setItem('stickyChatInput', 'true');
window.localStorage.setItem('playgroundComposerOptionsExpanded', 'false');
Expand Down
6 changes: 3 additions & 3 deletions apps/tldw-frontend/e2e/smoke/smoke.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,14 +411,14 @@
accessToken: cfg.accessToken
}

localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.setItem("isMigrated", "true")
// Backward-compat for routes still reading legacy top-level keys.
localStorage.setItem("serverUrl", cfg.serverUrl)
localStorage.setItem("tldwServerUrl", cfg.serverUrl)
localStorage.setItem("authMode", cfg.authMode)
localStorage.setItem("apiKey", cfg.apiKey) // lgtm[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key
localStorage.setItem("accessToken", cfg.accessToken) // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
localStorage.setItem("apiKey", cfg.apiKey) // codeql[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.setItem("accessToken", cfg.accessToken) // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
localStorage.setItem("__tldw_first_run_complete", "true")
localStorage.setItem("assistant_setup_dismissed", "true")
localStorage.setItem("__tldw_test_bypass", "true")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
}

try {
localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
localStorage.setItem("tldwConfig", JSON.stringify(authConfig)) // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.setItem("isMigrated", "true")
localStorage.setItem("__tldw_first_run_complete", "true")
localStorage.setItem("assistant_setup_dismissed", "true")
localStorage.setItem("serverUrl", cfg.serverUrl)
localStorage.setItem("tldwServerUrl", cfg.serverUrl)
localStorage.setItem("tldw-api-host", cfg.serverUrl)
localStorage.setItem("authMode", "single-user")
localStorage.setItem("apiKey", cfg.apiKey) // lgtm[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key
localStorage.setItem("apiKey", cfg.apiKey) // codeql[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to apiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.removeItem("__tldw_allow_offline")
localStorage.removeItem("__tldw_test_bypass")
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,12 @@
localStorage.setItem(key, JSON.stringify(value));
};

localStorage.setItem('tldwConfig', JSON.stringify(config)); // lgtm[js/clear-text-storage-of-sensitive-data] test-only browser auth seed for real-server E2E
localStorage.setItem('tldwConfig', JSON.stringify(config)); // codeql[js/clear-text-storage-of-sensitive-data] test-only browser auth seed for real-server E2E

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to configuredApiKey
as clear text.
This stores sensitive data returned by
an access to configuredApiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.setItem('serverUrl', configuredServerUrl);
localStorage.setItem('tldwServerUrl', configuredServerUrl);
localStorage.setItem('tldw-api-host', configuredServerUrl);
localStorage.setItem('authMode', 'single-user');
localStorage.setItem('apiKey', configuredApiKey); // lgtm[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key
localStorage.setItem('apiKey', configuredApiKey); // codeql[js/clear-text-storage-of-sensitive-data] test-only legacy auth compatibility key

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High test

This stores sensitive data returned by
an access to configuredApiKey
as clear text.
This stores sensitive data returned by
an access to configuredApiKey
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
localStorage.setItem('isMigrated', 'true');
localStorage.setItem('__tldw_first_run_complete', 'true');
localStorage.setItem('assistant_setup_dismissed', 'true');
Expand Down Expand Up @@ -398,7 +398,7 @@
}
}
if (configuredPersistedServerChatId) {
localStorage.setItem( // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E persisted chat fixture
localStorage.setItem( // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E persisted chat fixture
'tldw-playground-session',
JSON.stringify({
state: {
Expand Down
2 changes: 1 addition & 1 deletion apps/tldw-frontend/e2e/workflows/media-review.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const seedAppAuthWithApiKey = async (page: import("@playwright/test").Page) => {
"tldwConfig",
JSON.stringify({
serverUrl: cfg.serverUrl,
// lgtm[js/clear-text-storage-of-sensitive-data] synthetic CI key only
// codeql[js/clear-text-storage-of-sensitive-data] synthetic CI key only
apiKey: cfg.apiKey,
authMode: "single-user"
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ test.describe("Onboarding First-Source Journey", () => {
await installCompletedFirstRunApi(authedPage)
await authedPage.addInitScript((cfg) => {
try {
localStorage.setItem( // lgtm[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
localStorage.setItem( // codeql[js/clear-text-storage-of-sensitive-data] synthetic E2E auth seed only
"tldwConfig",
JSON.stringify({
serverUrl: cfg.serverUrl,
Expand Down
2 changes: 2 additions & 0 deletions apps/tldw-frontend/extension/shims/runtime-bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@

if (initialServerUrl && explicitWebHost !== initialServerUrl) {
try {
// codeql[js/clear-text-storage-of-sensitive-data]: tldw-api-host stores non-secret server metadata only.

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
an access to apiKey
as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to configuredApiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to configuredApiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
window.localStorage.setItem("tldw-api-host", initialServerUrl)
} catch {
// Best-effort only; ignore storage failures in web contexts.
Expand All @@ -501,7 +502,8 @@
if (!serverUrl && !apiKey && !apiBearer) return

if (serverUrl && initialServerUrl !== serverUrl) {
try {

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
an access to apiKey
as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to configuredApiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to configuredApiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
This stores sensitive data returned by an access to apiKey as clear text.
// codeql[js/clear-text-storage-of-sensitive-data]: tldw-api-host stores non-secret server metadata only.
window.localStorage.setItem("tldw-api-host", serverUrl)
} catch {
// Best-effort only; ignore storage failures in web contexts.
Expand Down
50 changes: 45 additions & 5 deletions apps/tldw-frontend/hooks/__tests__/useConfig.networking.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const authStorageMocks = vi.hoisted(() => ({

vi.mock('@web/lib/authStorage', () => authStorageMocks);

function readStoredTldwConfig(): Record<string, unknown> {
return JSON.parse(localStorage.getItem('tldwConfig') ?? '{}') as Record<string, unknown>;
}

describe('useConfig networking', () => {
beforeEach(() => {
vi.resetModules();
Expand Down Expand Up @@ -150,7 +154,7 @@ describe('useConfig networking', () => {
});
});

it('keeps manually entered single-user api keys in runtime memory only', async () => {
it('persists manually entered single-user api keys for reloads', async () => {
process.env.NEXT_PUBLIC_API_URL = 'http://127.0.0.1:8000';
localStorage.setItem('apiBearer', 'legacy-bearer');
localStorage.setItem('refreshToken', 'legacy-refresh');
Expand All @@ -167,12 +171,41 @@ describe('useConfig networking', () => {
await waitFor(() => {
expect(authStorageMocks.setRuntimeApiKey).toHaveBeenLastCalledWith('saved-api-key');
});
expect(localStorage.getItem('apiKey')).toBeNull();
expect(localStorage.getItem('apiKey')).toBe('saved-api-key');
expect(localStorage.getItem('apiBearer')).toBeNull();
expect(localStorage.getItem('tldwConfig')).not.toContain('saved-api-key');
expect(readStoredTldwConfig()).toMatchObject({
authMode: 'single-user',
apiKey: 'saved-api-key',
});
expect(readStoredTldwConfig()).not.toHaveProperty('accessToken');
expect(localStorage.getItem('refreshToken')).toBeNull();
});

it('persists manually entered multi-user bearer tokens for reloads', async () => {
process.env.NEXT_PUBLIC_API_URL = 'http://127.0.0.1:8000';
localStorage.setItem('apiKey', 'legacy-api-key');
const { ConfigProvider, useConfig } = await import('@web/hooks/useConfig');

const { result } = renderHook(() => useConfig(), {
wrapper: ({ children }) => <ConfigProvider>{children}</ConfigProvider>,
});

act(() => {
result.current.setApiBearer('Bearer saved-bearer-token');
});

await waitFor(() => {
expect(authStorageMocks.setRuntimeApiBearer).toHaveBeenLastCalledWith('Bearer saved-bearer-token');
});
expect(localStorage.getItem('accessToken')).toBe('saved-bearer-token');
expect(localStorage.getItem('apiKey')).toBeNull();
expect(readStoredTldwConfig()).toMatchObject({
authMode: 'multi-user',
accessToken: 'saved-bearer-token',
});
expect(readStoredTldwConfig()).not.toHaveProperty('apiKey');
});

it('refreshes live config after settings writes canonical tldw config', async () => {
process.env.NEXT_PUBLIC_API_URL = 'http://127.0.0.1:8000';
const { ConfigProvider, useConfig } = await import('@web/hooks/useConfig');
Expand All @@ -198,8 +231,12 @@ describe('useConfig networking', () => {
expect(result.current.config.apiBaseHost).toBe('http://127.0.0.1:8222');
expect(authStorageMocks.setRuntimeApiKey).toHaveBeenLastCalledWith('event-api-key');
});
expect(localStorage.getItem('apiKey')).toBeNull();
expect(localStorage.getItem('tldwConfig')).not.toContain('event-api-key');
expect(localStorage.getItem('apiKey')).toBe('event-api-key');
expect(readStoredTldwConfig()).toMatchObject({
authMode: 'single-user',
apiKey: 'event-api-key',
});
expect(readStoredTldwConfig()).not.toHaveProperty('accessToken');
});

it('keeps environment api keys ahead of stale browser config', async () => {
Expand All @@ -224,5 +261,8 @@ describe('useConfig networking', () => {
await waitFor(() => {
expect(authStorageMocks.setRuntimeApiKey).toHaveBeenLastCalledWith('env-api-key');
});
expect(localStorage.getItem('apiKey')).toBeNull();
expect(readStoredTldwConfig()).not.toHaveProperty('apiKey');
expect(readStoredTldwConfig()).not.toHaveProperty('accessToken');
});
});
Loading
Loading