-
Notifications
You must be signed in to change notification settings - Fork 56
Bug-Squash/'Works-on-my-machine' - 4 PRDs in one PR :( 👎 #679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
400e500
8e73c04
27f74b7
b2800ca
2129647
ccd63bf
96adaac
bc49d4c
48f9795
8d3026d
4c4e8bf
18bea9c
f3f7ad6
5439691
7f93757
90e527e
9763ca2
13d1030
ffd1c7b
a18f8e6
9063223
f5ec492
a5d3ef5
1c9903c
4a53e49
da7ad02
bfc8aae
1486e6d
45ebef0
b93b11d
a6afe1f
349db3d
2245814
00f1036
a9d62ce
066917c
0d66be8
e6a36f6
79f888f
96ebea9
9d84bec
ee86363
8f687b5
3c4abe7
599c624
3e36a12
a5e8e71
bced400
9972090
9e1a1f4
89c9ca7
c646195
bd9f956
f0a84ab
e6c46b2
55a4e9c
c78b84c
069fcee
24f56a0
4e6702c
33f1784
c14a69b
ed6319a
a78f177
8f08b9e
c6b2457
ff9ff41
566d459
aa89995
445c358
bd4cffc
32cd014
0bab803
6029568
120a414
131f9de
0dd9626
54ecd44
5b571fd
929c5ef
654828b
c289fa5
52b938e
e66993d
1ac6b84
06f5990
846fbe2
d5e88c9
4c974d4
a6d4ee7
63d9177
04f0d25
65341b4
f15c87d
ce8dc64
8248dab
3fc692f
71b1942
ad82dfd
7383a85
c83067a
a323328
acf9eac
b1f242e
d7a9510
de1795d
3e97878
bb7c863
cbfbfe5
51d69a7
bdc05dd
87e36bf
3f72df3
34f415f
b3fb41d
048239a
1913084
5cdccf9
b89f1c2
e793bf0
7dfd54f
ffb5b18
e4a3046
5bde366
4a0f332
c74b53d
cfc9b73
b311945
f3cbe53
8edcaf4
dd49bf4
6361039
ed8407d
8606329
6e27b9a
0fe8518
2e63935
c21cd15
9e59bb1
5986489
1b6642a
d607229
46f40d1
2be045c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,24 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| # Run on direct pushes to protected branches only | ||
| push: | ||
| branches: | ||
| - main | ||
| - dev | ||
| # Run CI for PRs targeting these branches | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| - dev | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | ||
| # Ensure push and PR for the same commit share one slot | ||
| group: ci-${{ github.event.pull_request.head.sha || github.sha }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| lint: | ||
|
|
@@ -83,6 +88,8 @@ jobs: | |
| TEST_DB_HOST: 127.0.0.1 | ||
| TEST_DB_USER: tldw | ||
| TEST_DB_PASSWORD: tldw | ||
| # Align AuthNZ_Postgres conftest default DB name with tests | ||
| TEST_DB_NAME: tldw_test | ||
| TLDW_TEST_POSTGRES_REQUIRED: '1' | ||
| steps: | ||
| - name: Checkout | ||
|
|
@@ -115,6 +122,18 @@ jobs: | |
| run: | | ||
| echo "POSTGRES_TEST_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV" | ||
| echo "TEST_DB_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV" | ||
| # Provide a unified DSN so any test preferring TEST_DATABASE_URL uses the right DB | ||
| echo "TEST_DATABASE_URL=postgresql://tldw:[email protected]:${{ job.services.postgres.ports[5432] }}/tldw_content" >> "$GITHUB_ENV" | ||
| echo "DATABASE_URL=postgresql://tldw:[email protected]:${{ job.services.postgres.ports[5432] }}/tldw_content" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Ensure base DB exists | ||
| shell: bash | ||
| env: | ||
| PGPASSWORD: tldw | ||
| run: | | ||
| PORT="${{ job.services.postgres.ports[5432] }}" | ||
| psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='tldw_content'" | grep -q 1 || \ | ||
| psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -c "CREATE DATABASE tldw_content" | ||
|
|
||
| - name: Install additional deps for PG tests | ||
| run: | | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -21,40 +21,102 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Setup Python | ||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/setup-python@v5 | ||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||
| python-version: '3.12' | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Generate Python SBOM (CycloneDX) | ||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||
| python -m pip install -q cyclonedx-python | ||||||||||||||||||||||||||||||||||||||||||||
| GEN_CMD="python -m cyclonedx_py" | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "${pythonLocation:-}" ] && [ -x "${pythonLocation}/bin/cyclonedx-py" ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| GEN_CMD="${pythonLocation}/bin/cyclonedx-py"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| elif command -v cyclonedx-py >/dev/null 2>&1; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| GEN_CMD="cyclonedx-py"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
| gen_from_requirements() { \ | ||||||||||||||||||||||||||||||||||||||||||||
| local req="$1"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "Generating Python SBOM from ${req} using ${GEN_CMD}"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| ${GEN_CMD} -r "${req}" --output-file sbom-python.cdx.json || { \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "Primary generator failed; attempting cyclonedx-bom fallback"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| python -m pip install -q cyclonedx-bom || true; \ | ||||||||||||||||||||||||||||||||||||||||||||
| if command -v cyclonedx-bom >/dev/null 2>&1; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| cyclonedx-bom -r "${req}" -o sbom-python.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| else \ | ||||||||||||||||||||||||||||||||||||||||||||
| python -m cyclonedx_bom -r "${req}" -o sbom-python.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi; \ | ||||||||||||||||||||||||||||||||||||||||||||
| }; \ | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -f tldw_Server_API/requirements.txt ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| gen_from_requirements tldw_Server_API/requirements.txt; \ | ||||||||||||||||||||||||||||||||||||||||||||
| elif [ -f requirements.txt ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| gen_from_requirements requirements.txt; \ | ||||||||||||||||||||||||||||||||||||||||||||
| else \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "No requirements file found; cannot generate SBOM"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| exit 1; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| # No registry login required for public Docker Hub images used below | ||||||||||||||||||||||||||||||||||||||||||||
| - name: Setup Node | ||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/setup-node@v6 | ||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/setup-node@v4 | ||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||
| node-version: '20' | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Generate Python SBOM from pyproject (cdxgen) | ||||||||||||||||||||||||||||||||||||||||||||
| - name: Generate Node SBOM (CycloneDX NPM) | ||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -f pyproject.toml ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| npx @appthreat/cdxgen -t python -o sbom-python.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -f package-lock.json ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| elif [ -f tldw-frontend/package-lock.json ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| (cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \ | ||||||||||||||||||||||||||||||||||||||||||||
| else \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "No package-lock.json found; skipping Node SBOM"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
101
to
109
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling to the Node SBOM generation step for consistency. The "Generate Node SBOM (CycloneDX NPM)" step lacks While the Node SBOM generation is intentionally optional (skipped if no package-lock.json exists), command failures should still cause the job to fail. Apply this diff to add error handling: - name: Generate Node SBOM (CycloneDX NPM)
run: |
+ set -euo pipefail
if [ -f package-lock.json ]; then \
npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \
elif [ -f tldw-frontend/package-lock.json ]; then \
(cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \
else \
echo "No package-lock.json found; skipping Node SBOM"; \
fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Set up Docker Buildx | ||||||||||||||||||||||||||||||||||||||||||||
| uses: docker/setup-buildx-action@v3 | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Resolve CycloneDX CLI digest | ||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||
| ref="ghcr.io/cyclonedx/cyclonedx-cli:0.30.0" | ||||||||||||||||||||||||||||||||||||||||||||
| echo "Resolving digest for ${ref}" | ||||||||||||||||||||||||||||||||||||||||||||
| # Prefer buildx imagetools; fallback to manifest inspect if needed | ||||||||||||||||||||||||||||||||||||||||||||
| if docker buildx imagetools inspect "$ref" >/dev/null 2>&1; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| digest=$(docker buildx imagetools inspect "$ref" | awk '/^Digest:/ {print $2; exit}'); \ | ||||||||||||||||||||||||||||||||||||||||||||
| else \ | ||||||||||||||||||||||||||||||||||||||||||||
| digest=$(docker manifest inspect "$ref" | jq -r '.manifests[0].digest' || true); \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "${digest:-}" ] || ! echo "$digest" | grep -Eq '^sha256:[0-9a-f]{64}$'; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "Failed to resolve digest for $ref"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| exit 1; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
| echo "CDX_CLI_DIGEST=$digest" >> "$GITHUB_ENV" | ||||||||||||||||||||||||||||||||||||||||||||
| echo "Resolved digest: $digest" | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Generate SBOM (CycloneDX JSON) | ||||||||||||||||||||||||||||||||||||||||||||
| uses: anchore/sbom-action@8e94d75ddd33f69f691467e42275782e4bfefe84 # v0.20.9 | ||||||||||||||||||||||||||||||||||||||||||||
| - name: Merge SBOMs (CycloneDX CLI) | ||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||
| if [ -f sbom-python.cdx.json ] && [ -f sbom-node.cdx.json ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm -v "$PWD":/work -w /work ghcr.io/cyclonedx/cyclonedx-cli@${CDX_CLI_DIGEST} \ | ||||||||||||||||||||||||||||||||||||||||||||
| merge --input-files sbom-python.cdx.json sbom-node.cdx.json --output-file sbom.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| elif [ -f sbom-python.cdx.json ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| cp sbom-python.cdx.json sbom.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| elif [ -f sbom-node.cdx.json ]; then \ | ||||||||||||||||||||||||||||||||||||||||||||
| cp sbom-node.cdx.json sbom.cdx.json; \ | ||||||||||||||||||||||||||||||||||||||||||||
| else \ | ||||||||||||||||||||||||||||||||||||||||||||
| echo "No SBOMs generated"; \ | ||||||||||||||||||||||||||||||||||||||||||||
| exit 1; \ | ||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||
rmusser01 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Upload SBOM artifact | ||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | ||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||
| path: . | ||||||||||||||||||||||||||||||||||||||||||||
| format: cyclonedx-json | ||||||||||||||||||||||||||||||||||||||||||||
| output-file: sbom.cdx.json | ||||||||||||||||||||||||||||||||||||||||||||
| upload-artifact: true | ||||||||||||||||||||||||||||||||||||||||||||
| artifact-name: sbom-cyclonedx | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Validate SBOM (CycloneDX CLI - pinned) | ||||||||||||||||||||||||||||||||||||||||||||
| id: validate_cli_pinned | ||||||||||||||||||||||||||||||||||||||||||||
| name: sbom-cyclonedx | ||||||||||||||||||||||||||||||||||||||||||||
| path: sbom.cdx.json | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Validate SBOM (CycloneDX CLI - pinned digest) | ||||||||||||||||||||||||||||||||||||||||||||
| if: ${{ hashFiles('sbom.cdx.json') != '' }} | ||||||||||||||||||||||||||||||||||||||||||||
| continue-on-error: true | ||||||||||||||||||||||||||||||||||||||||||||
| uses: docker://cyclonedx/cyclonedx-cli:0.30.0 | ||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||
| args: >- | ||||||||||||||||||||||||||||||||||||||||||||
| validate --input-file sbom.cdx.json | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - name: Validate SBOM (CycloneDX CLI - pinned fallback) | ||||||||||||||||||||||||||||||||||||||||||||
| if: ${{ hashFiles('sbom.cdx.json') != '' && steps.validate_cli_pinned.outcome == 'failure' }} | ||||||||||||||||||||||||||||||||||||||||||||
| uses: docker://cyclonedx/cyclonedx-cli:0.29.1 | ||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||
| args: >- | ||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm -v "$PWD":/work -w /work ghcr.io/cyclonedx/cyclonedx-cli@${CDX_CLI_DIGEST} \ | ||||||||||||||||||||||||||||||||||||||||||||
| validate --input-file sbom.cdx.json | ||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| ## Implementation Plan — Browser Extension | ||
|
|
||
| This document tracks staged implementation with concrete success criteria and test notes. | ||
|
|
||
| --- | ||
|
|
||
| ## Stage 1: Connectivity & Auth | ||
| **Goal**: Establish server connectivity and both auth modes (API Key and JWT). | ||
|
|
||
| **Success Criteria**: | ||
| - Options page captures server URL and credentials; health check returns OK. | ||
| - Background proxy injects headers; tokens never exposed to content scripts. | ||
| - 401 triggers single‑flight refresh and one retry; no duplicate requests. | ||
|
|
||
| **Tests**: | ||
| - Unit: auth storage, header injection, refresh queue. | ||
| - Integration: health endpoint, login/logout, API key validation. | ||
| - Manual: revoke permission and re‑grant host permission flow. | ||
|
|
||
| **Status**: Not Started | ||
|
|
||
| --- | ||
|
|
||
| ## Stage 2: Chat & Models | ||
| **Goal**: Streaming chat via `/api/v1/chat/completions` with model selection. | ||
|
|
||
| **Success Criteria**: | ||
| - Models/providers fetched and rendered; selection persisted per session. | ||
| - Non‑stream and SSE stream both work; cancel stops network within ~200ms. | ||
| - Exact path strings (no 307 redirects observed in logs). | ||
|
|
||
| **Tests**: | ||
| - Unit: SSE parser, backoff, abort controller. | ||
| - Integration: stream across two models; cancel and resume. | ||
| - Manual: slow network simulation; ensure UI stays responsive. | ||
|
|
||
| **Status**: Not Started | ||
|
|
||
| --- | ||
|
|
||
| ## Stage 3: RAG & Media | ||
| **Goal**: RAG search UI and URL ingest with progress notifications. | ||
|
|
||
| **Success Criteria**: | ||
| - RAG `/api/v1/rag/search` returns results; snippets insert into chat context. | ||
| - URL ingest calls `/api/v1/media/process`; user sees progress and final status. | ||
| - Errors are actionable (permission, size limits, server busy). | ||
|
|
||
| **Tests**: | ||
| - Unit: request builders, snippet insertion. | ||
| - Integration: RAG queries; media process happy path and failure modes. | ||
| - Manual: ingest current tab URL; verify server reflects new media. | ||
|
|
||
| **Status**: Not Started | ||
|
|
||
| --- | ||
|
|
||
| ## Stage 4: Notes/Prompts & STT | ||
| **Goal**: Notes/Prompts basic flows and STT upload/transcribe. | ||
|
|
||
| **Success Criteria**: | ||
| - Notes: create/search; export works; selection‑to‑note from content script. | ||
| - Prompts: browse/import/export; insert chosen prompt into chat input. | ||
| - STT: upload short clip; transcript displayed; non‑supported formats fail clearly. | ||
|
|
||
| **Tests**: | ||
| - Unit: notes/prompts stores; MIME/type validation. | ||
| - Integration: `/api/v1/notes/*`, `/api/v1/prompts/*`, `/api/v1/audio/transcriptions`. | ||
| - Manual: 20s audio clip round‑trip; error message clarity for oversized files. | ||
|
|
||
| **Status**: Not Started | ||
|
|
||
| --- | ||
|
|
||
| ## Stage 5: TTS & Polish | ||
| **Goal**: TTS synthesis/playback and UX polish. | ||
|
|
||
| **Success Criteria**: | ||
| - Voices list loads from `/api/v1/audio/voices/catalog`; selection persisted. | ||
| - `/api/v1/audio/speech` returns audio; playback controls functional. | ||
| - Accessibility audit passes key checks; performance within budgets. | ||
|
|
||
| **Tests**: | ||
| - Unit: audio player controls and error states. | ||
| - Integration: voices catalog and synthesis endpoints. | ||
| - Manual: latency spot checks; keyboard navigation. | ||
|
|
||
| **Status**: Not Started | ||
|
|
||
| --- | ||
|
|
||
| ## Notes | ||
| - Centralize route constants and validate against OpenAPI at startup (warn on mismatch). | ||
| - Keep tokens in background memory; only persist refresh tokens if strictly necessary. | ||
| - Use optional host permissions for user‑configured origins (Chrome/Edge MV3). | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.