Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 0 additions & 4 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
**Learning:** When native disabled buttons are wrapped in a focusable `span` to provide accessible tooltips, tests that previously found and clicked the `button` (by temporarily removing the `disabled` attribute) may fail or become overly complex. It is cleaner and more accurate to query the wrapper element (e.g. via its `title`) and fire events on it, reflecting the actual accessible DOM structure.
**Action:** When testing UI components that wrap disabled buttons in a focusable span for accessibility (e.g., using a tooltip/title), use `screen.getByTitle(...)` to query the wrapper element for interactions like `fireEvent.click` rather than `screen.getByRole('button')`.

## 2024-05-24 - Avoid nesting native buttons with ARIA role button on wrappers
**Learning:** Adding `role="button"` to a `span` or `div` wrapper that contains a native `<button>` element inside violates ARIA specifications. Interactive roles (like `button`) must not contain other interactive elements (even if the inner element is disabled or has `aria-hidden`), as this causes invalid/redundant accessibility trees and screen reader confusion.
**Action:** Always verify wrappers used to implement tooltips for disabled buttons are standard elements (e.g., `<span tabIndex={0} title="...">`) but *do not* assign `role="button"` to the wrapper itself.

## 2026-07-02 - Inline clear buttons preserve focus
**Learning:** Inline clear buttons often unmount immediately after clearing state, which can drop keyboard focus to the document body.
**Action:** Move focus back to the owning input before clearing state, and cover the behavior with a DOM focus test.
2 changes: 1 addition & 1 deletion .github/workflows/bandit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand Down
90 changes: 18 additions & 72 deletions .github/workflows/build-baseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand All @@ -62,19 +62,12 @@ jobs:
}

if (Get-Command Get-MpComputerStatus -ErrorAction SilentlyContinue) {
$status = $null
try {
$status = Get-MpComputerStatus -ErrorAction Stop
} catch {
Write-AntivirusEvidence "Antivirus check: Defender telemetry query failed: $($_.Exception.Message)."
}
if ($status) {
Write-AntivirusEvidence "Antivirus check: Defender status AntivirusEnabled=$($status.AntivirusEnabled) RealTimeProtectionEnabled=$($status.RealTimeProtectionEnabled)."
if ($status.AntivirusEnabled) {
return
}
Write-AntivirusEvidence "Antivirus check: Defender telemetry is present but antivirus is not reported as enabled on this hosted runner."
$status = Get-MpComputerStatus
Write-AntivirusEvidence "Antivirus check: Defender status AntivirusEnabled=$($status.AntivirusEnabled) RealTimeProtectionEnabled=$($status.RealTimeProtectionEnabled)."
if ($status.AntivirusEnabled) {
return
}
Write-AntivirusEvidence "Antivirus check: Defender telemetry is present but antivirus is not reported as enabled on this hosted runner."
}

$products = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct -ErrorAction SilentlyContinue
Expand All @@ -97,24 +90,14 @@ jobs:
- name: Build frontend
run: npm run build --workspace @bandscope/desktop
- name: Build native shell
env:
BANDSCOPE_TAURI_BUILD_ATTEMPTS: "3"
run: bash scripts/release/build_tauri_bundle_with_retry.sh @bandscope/desktop "$env:BANDSCOPE_TARGET_TRIPLE" nsis
run: npm exec --workspace @bandscope/desktop -- tauri build --target $env:BANDSCOPE_TARGET_TRIPLE --bundles nsis
- name: Package Windows amd64 artifact
run: python scripts/release/package_desktop_artifact.py
- name: Upload Windows amd64 artifact
id: upload-windows-amd64
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bandscope-windows-amd64-${{ github.sha }}
path: artifacts/*
- name: Explain non-blocking Windows amd64 artifact upload failure
if: ${{ steps.upload-windows-amd64.outcome == 'failure' }}
run: |
echo "Artifact upload failed after the Windows amd64 bundle was packaged." >> "$GITHUB_STEP_SUMMARY"
echo "Pull request builds keep artifact upload non-blocking because GitHub artifact service or DNS failures do not invalidate the build evidence." >> "$GITHUB_STEP_SUMMARY"
echo "Tag and release builds remain blocking because release publication requires uploaded artifacts." >> "$GITHUB_STEP_SUMMARY"

build-windows-arm64:
name: build / windows / arm64
Expand All @@ -138,7 +121,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand All @@ -157,19 +140,12 @@ jobs:
}

if (Get-Command Get-MpComputerStatus -ErrorAction SilentlyContinue) {
$status = $null
try {
$status = Get-MpComputerStatus -ErrorAction Stop
} catch {
Write-AntivirusEvidence "Antivirus check: Defender telemetry query failed: $($_.Exception.Message)."
}
if ($status) {
Write-AntivirusEvidence "Antivirus check: Defender status AntivirusEnabled=$($status.AntivirusEnabled) RealTimeProtectionEnabled=$($status.RealTimeProtectionEnabled)."
if ($status.AntivirusEnabled) {
return
}
Write-AntivirusEvidence "Antivirus check: Defender telemetry is present but antivirus is not reported as enabled on this hosted runner."
$status = Get-MpComputerStatus
Write-AntivirusEvidence "Antivirus check: Defender status AntivirusEnabled=$($status.AntivirusEnabled) RealTimeProtectionEnabled=$($status.RealTimeProtectionEnabled)."
if ($status.AntivirusEnabled) {
return
}
Write-AntivirusEvidence "Antivirus check: Defender telemetry is present but antivirus is not reported as enabled on this hosted runner."
}

$products = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct -ErrorAction SilentlyContinue
Expand All @@ -193,24 +169,14 @@ jobs:
- name: Build frontend
run: npm run build --workspace @bandscope/desktop
- name: Build native shell
env:
BANDSCOPE_TAURI_BUILD_ATTEMPTS: "3"
run: bash scripts/release/build_tauri_bundle_with_retry.sh @bandscope/desktop "$env:BANDSCOPE_TARGET_TRIPLE" nsis
run: npm exec --workspace @bandscope/desktop -- tauri build --target $env:BANDSCOPE_TARGET_TRIPLE --bundles nsis
- name: Package Windows arm64 artifact
run: python scripts/release/package_desktop_artifact.py
- name: Upload Windows arm64 artifact
id: upload-windows-arm64
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bandscope-windows-arm64-${{ github.sha }}
path: artifacts/*
- name: Explain non-blocking Windows arm64 artifact upload failure
if: ${{ steps.upload-windows-arm64.outcome == 'failure' }}
run: |
echo "Artifact upload failed after the Windows arm64 bundle was packaged." >> "$GITHUB_STEP_SUMMARY"
echo "Pull request builds keep artifact upload non-blocking because GitHub artifact service or DNS failures do not invalidate the build evidence." >> "$GITHUB_STEP_SUMMARY"
echo "Tag and release builds remain blocking because release publication requires uploaded artifacts." >> "$GITHUB_STEP_SUMMARY"

gate-windows:
name: gate / build / windows
Expand Down Expand Up @@ -244,7 +210,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand All @@ -259,24 +225,14 @@ jobs:
- name: Build frontend
run: npm run build --workspace @bandscope/desktop
- name: Build native shell
env:
BANDSCOPE_TAURI_BUILD_ATTEMPTS: "2"
run: bash scripts/release/build_tauri_bundle_with_retry.sh @bandscope/desktop "$BANDSCOPE_TARGET_TRIPLE" dmg
run: npm exec --workspace @bandscope/desktop -- tauri build --target "$BANDSCOPE_TARGET_TRIPLE" --bundles dmg
- name: Package macOS amd64 artifact
run: python3 scripts/release/package_desktop_artifact.py
- name: Upload macOS amd64 artifact
id: upload-macos-amd64
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bandscope-macos-amd64-${{ github.sha }}
path: artifacts/*
- name: Explain non-blocking macOS amd64 artifact upload failure
if: ${{ steps.upload-macos-amd64.outcome == 'failure' }}
run: |
echo "Artifact upload failed after the macOS amd64 bundle was packaged." >> "$GITHUB_STEP_SUMMARY"
echo "Pull request builds keep artifact upload non-blocking because GitHub artifact service or DNS failures do not invalidate the build evidence." >> "$GITHUB_STEP_SUMMARY"
echo "Tag and release builds remain blocking because release publication requires uploaded artifacts." >> "$GITHUB_STEP_SUMMARY"

build-macos-arm64:
name: build / macos / arm64
Expand All @@ -300,7 +256,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand All @@ -315,24 +271,14 @@ jobs:
- name: Build frontend
run: npm run build --workspace @bandscope/desktop
- name: Build native shell
env:
BANDSCOPE_TAURI_BUILD_ATTEMPTS: "2"
run: bash scripts/release/build_tauri_bundle_with_retry.sh @bandscope/desktop "$BANDSCOPE_TARGET_TRIPLE" dmg
run: npm exec --workspace @bandscope/desktop -- tauri build --target "$BANDSCOPE_TARGET_TRIPLE" --bundles dmg
- name: Package macOS arm64 artifact
run: python3 scripts/release/package_desktop_artifact.py
- name: Upload macOS arm64 artifact
id: upload-macos-arm64
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: bandscope-macos-arm64-${{ github.sha }}
path: artifacts/*
- name: Explain non-blocking macOS arm64 artifact upload failure
if: ${{ steps.upload-macos-arm64.outcome == 'failure' }}
run: |
echo "Artifact upload failed after the macOS arm64 bundle was packaged." >> "$GITHUB_STEP_SUMMARY"
echo "Pull request builds keep artifact upload non-blocking because GitHub artifact service or DNS failures do not invalidate the build evidence." >> "$GITHUB_STEP_SUMMARY"
echo "Tag and release builds remain blocking because release publication requires uploaded artifacts." >> "$GITHUB_STEP_SUMMARY"

gate-macos:
name: gate / build / macos
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
with:
node-version: 22.22.3
cache: npm
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand Down Expand Up @@ -56,5 +56,3 @@ jobs:
run: npm run build --workspace @bandscope/desktop
- name: Check Tauri shell
run: cargo +stable check --manifest-path apps/desktop/src-tauri/Cargo.toml --locked
- name: Test Tauri shell
run: cargo +stable test --manifest-path apps/desktop/src-tauri/Cargo.toml --locked
11 changes: 7 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ on:
branches:
- develop
- main
workflow_dispatch:
pull_request:
branches:
- develop
- main

permissions:
actions: read
Expand All @@ -32,8 +35,8 @@ jobs:
- python
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
- uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
languages: ${{ matrix.language }}
- uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
- uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
- uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
- uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
30 changes: 30 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: dependency-review

on:
pull_request:
branches:
- develop
- main

permissions:
contents: read

env:
GIT_CONFIG_COUNT: "1"
GIT_CONFIG_KEY_0: init.defaultBranch
GIT_CONFIG_VALUE_0: develop

jobs:
dependency-review:
name: dependency-review
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high
16 changes: 10 additions & 6 deletions .github/workflows/ossf-scorecard.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
name: ossf-scorecard

on:
workflow_dispatch:
pull_request:
branches:
- develop
- main
schedule:
- cron: '30 1 * * 1'
push:
Expand All @@ -27,21 +30,21 @@ jobs:
with:
persist-credentials: false
- uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
if: github.event_name == 'pull_request' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
with:
results_file: results.sarif
results_format: sarif
publish_results: ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
if: github.event_name == 'pull_request' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
with:
name: ossf-scorecard-results
path: results.sarif
retention-days: 5
scorecard-sarif-upload:
name: scorecard-sarif-upload
needs: analysis
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
if: github.event_name == 'pull_request' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
runs-on: ubuntu-latest
permissions:
actions: read
Expand All @@ -63,7 +66,8 @@ jobs:
with:
persist-credentials: false
path: trusted-scorecard-scripts
ref: ${{ github.ref_name }}
# PR uploads keep the main checkout on the merge ref while scripts come from the trusted base branch.
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.ref_name }}
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ossf-scorecard-results
Expand All @@ -79,6 +83,6 @@ jobs:
python3 trusted-scorecard-scripts/scripts/checks/normalize_scorecard_sarif.py
scorecard-sarif/results.sarif
normalized-scorecard-results.sarif
- uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 peeled commit; SHA pinning retained as supply-chain attack mitigation.
- uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 peeled commit; SHA pinning retained as supply-chain attack mitigation.
with:
sarif_file: normalized-scorecard-results.sarif
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/security-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: "0.8.6"
enable-cache: false
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/trivy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: trivy

on:
pull_request:
branches:
- develop
- main
push:
branches:
- develop
Expand Down Expand Up @@ -31,13 +35,12 @@ jobs:
version: v0.71.2
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH,MEDIUM
severity: CRITICAL,HIGH
limit-severities-for-sarif: true
exit-code: '1'
skip-dirs: 'services/analysis-engine/.venv'
trivyignores: ./.trivyignore
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 peeled commit; SHA pinning retained as supply-chain attack mitigation.
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 peeled commit; SHA pinning retained as supply-chain attack mitigation.
if: always()
with:
sarif_file: trivy-results.sarif
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ __pycache__/
.mypy_cache/
.ruff_cache/
apps/desktop/src-tauri/target/
/target/
*.pyc
*.pyo
*.egg-info/
Expand Down
Loading
Loading