Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
18 changes: 18 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Automatically activate Python venv and sync dependencies on cd
# Requires: direnv (https://direnv.net/)
# Install: sudo apt install direnv && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

# Create venv if it doesn't exist
if [[ ! -d .venv ]]; then
echo "Creating .venv with uv..."
uv venv .venv
fi

# Activate the venv
source .venv/bin/activate

# Ensure dependencies are synced
uv sync --quiet

# Set PYO3 to use this venv's Python
export PYO3_PYTHON="${PWD}/.venv/bin/python"
80 changes: 49 additions & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:
# Security scanning for vulnerabilities and license compliance
security_audit:
name: Security Audit
runs-on: [self-hosted, Linux, X64, fedora, nobara]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.0

Expand All @@ -118,28 +118,28 @@ jobs:
run: cargo deny check

# Build, check, and test with multiple Rust versions
build_and_check:
name: Build & Test
runs-on: [self-hosted, Linux, X64, fedora, nobara]
unit_tests_hosted:
name: Unit Tests & Golden Master (Hosted)
runs-on: ubuntu-latest
needs: [setup-whisper-dependencies]
strategy:
matrix:
rust-version: [stable] # Use stable only
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.0

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y xdotool wget unzip gcc g++ make xvfb openbox dbus-x11 wl-clipboard xclip ydotool x11-utils wmctrl pkg-config pulseaudio libasound2-dev libgtk-3-dev libatspi-dev libxtst-dev python3-pip python3-venv
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The unit_tests_hosted job installs many hardware and display-related system dependencies (xdotool, xvfb, openbox, dbus-x11, wl-clipboard, xclip, ydotool, x11-utils, wmctrl, pulseaudio, libasound2-dev, libgtk-3-dev, libatspi-dev, libxtst-dev) on the hosted runner. This contradicts the PR's stated goal of running only non-hardware-dependent tests on hosted runners. If these tests truly don't require display servers or audio hardware, these dependencies should be removed. If they do require them, those tests should be moved to the hardware integration tests job on the self-hosted runner.

Suggested change
sudo apt-get install -y xdotool wget unzip gcc g++ make xvfb openbox dbus-x11 wl-clipboard xclip ydotool x11-utils wmctrl pkg-config pulseaudio libasound2-dev libgtk-3-dev libatspi-dev libxtst-dev python3-pip python3-venv
sudo apt-get install -y wget unzip gcc g++ make pkg-config python3-pip python3-venv

Copilot uses AI. Check for mistakes.

- name: Set up Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.rust-version }}
components: rustfmt, clippy
override: true

- name: Setup ColdVox
uses: ./.github/actions/setup-coldvox
with:
skip-toolchain: "true"

# Only run formatting and linting on stable
- name: Check formatting (advisory)
if: matrix.rust-version == 'stable'
Expand Down Expand Up @@ -181,17 +181,24 @@ jobs:
echo "=== Running Tests ==="
cargo test --workspace --locked --

- name: Run Golden Master pipeline test
if: matrix.rust-version == 'stable'
env:
WHISPER_MODEL_PATH: ${{ needs.setup-whisper-dependencies.outputs.model_path }}
WHISPER_MODEL_SIZE: ${{ needs.setup-whisper-dependencies.outputs.model_size }}
run: |
echo "=== Running Golden Master Test ==="
# Install Python dependencies for Golden Master
pip install faster-whisper
export PYTHONPATH=$(python3 -c "import site; print(site.getsitepackages()[0])")
cargo test -p coldvox-app --test golden_master -- --nocapture
Comment on lines +190 to +200
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The Golden Master test is now running on ubuntu-latest hosted runner, but it depends on setup-whisper-dependencies job which runs on the self-hosted runner and sets up the model in that runner's local filesystem. The WHISPER_MODEL_PATH output from setup-whisper-dependencies (which points to a path on the self-hosted runner) will not be accessible on the hosted runner. The Golden Master test needs either: 1) its own setup step to download the model on the hosted runner, 2) the model to be uploaded as an artifact and downloaded, or 3) to run on the self-hosted runner like before.

Copilot uses AI. Check for mistakes.

# GUI groundwork check integrated here
- name: Detect and test Qt 6 GUI
if: matrix.rust-version == 'stable'
run: |
if bash scripts/ci/detect-qt6.sh
then
echo "✅ Qt 6 detected - building GUI"
cargo check -p coldvox-gui --features qt-ui --locked
else
echo "⚠️ Qt 6 not detected - skipping GUI build"
fi
# Qt6 might not be easily available on ubuntu-latest without extra actions, skipping for now or adding if needed
echo "Skipping Qt6 check on hosted runner"

- name: Upload test artifacts on failure
if: failure()
Expand All @@ -204,7 +211,7 @@ jobs:
retention-days: 7

text_injection_tests:
name: Text Injection Tests
name: Hardware Integration Tests (Self-Hosted)
runs-on: [self-hosted, Linux, X64, fedora, nobara]
needs: [setup-whisper-dependencies]
timeout-minutes: 30
Expand All @@ -213,11 +220,26 @@ jobs:
RUST_LOG: debug
RUST_TEST_TIME_UNIT: 10000
RUST_TEST_TIME_INTEGRATION: 30000
RUSTC_WRAPPER: sccache
SCCACHE_DIR: /home/coldaine/.cache/sccache
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The SCCACHE_DIR is hardcoded to a specific user's home directory (/home/coldaine/.cache/sccache). This creates a tight coupling to a specific runner configuration and could fail if the runner username changes or if this job runs on a different runner. Consider using an environment variable or relative path like $HOME/.cache/sccache or the runner's temp directory.

Suggested change
SCCACHE_DIR: /home/coldaine/.cache/sccache
SCCACHE_DIR: $HOME/.cache/sccache

Copilot uses AI. Check for mistakes.
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.0
- uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: stable

# Use sccache if available on the runner
- name: Setup sccache
run: |
if command -v sccache >/dev/null; then
echo "sccache found"
sccache --start-server
else
echo "sccache not found, installing..."
cargo install sccache --locked || true
sccache --start-server
fi
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The sccache setup step attempts to start the server without checking if it's already running, which could cause errors on subsequent runs. Additionally, if the installation with cargo install fails (note the || true), the script continues to try starting the server which will fail. Consider checking if sccache is running before attempting to start it, and ensure proper error handling when sccache installation or startup fails.

Suggested change
if command -v sccache >/dev/null; then
echo "sccache found"
sccache --start-server
else
echo "sccache not found, installing..."
cargo install sccache --locked || true
sccache --start-server
fi
set -euo pipefail
if command -v sccache >/dev/null; then
echo "sccache found"
else
echo "sccache not found, installing..."
if ! cargo install sccache --locked; then
echo "Failed to install sccache. Proceeding without sccache."
exit 0
fi
fi
# Check if sccache server is already running
if sccache --show-stats >/dev/null 2>&1; then
echo "sccache server is already running."
else
echo "Starting sccache server..."
if ! sccache --start-server; then
echo "Failed to start sccache server. Proceeding without sccache."
exit 0
fi
fi

Copilot uses AI. Check for mistakes.

- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0

- name: Setup ColdVox
Expand Down Expand Up @@ -285,18 +307,14 @@ jobs:
- name: Build main application
run: cargo build --locked -p coldvox-app

- name: Run Golden Master pipeline test
- name: Run Hardware Capability Checks
env:
WHISPER_MODEL_PATH: ${{ needs.setup-whisper-dependencies.outputs.model_path }}
WHISPER_MODEL_SIZE: ${{ needs.setup-whisper-dependencies.outputs.model_size }}
COLDVOX_E2E_REAL_INJECTION: "1"
COLDVOX_E2E_REAL_AUDIO: "1"
run: |
echo "=== Golden Master Environment Validation ==="
echo "WHISPER_MODEL_PATH: $WHISPER_MODEL_PATH"
echo "WHISPER_MODEL_SIZE: $WHISPER_MODEL_SIZE"
echo "=== Running Golden Master Test ==="
pip install faster-whisper
export PYTHONPATH=$(python3 -c "import site; print(site.getsitepackages()[0])")
cargo test -p coldvox-app --test golden_master -- --nocapture
echo "=== Running Hardware Capability Checks ==="
# We run the new hardware_check test file, enabling the ignored tests
cargo test -p coldvox-app --test hardware_check -- --nocapture --include-ignored

- name: Upload test artifacts on failure
if: failure()
Expand Down Expand Up @@ -361,12 +379,12 @@ jobs:

ci_success:
name: CI Success Summary
runs-on: [self-hosted, Linux, X64, fedora, nobara]
runs-on: ubuntu-latest
needs:
- validate-workflows
- setup-whisper-dependencies
- security_audit
- build_and_check
- unit_tests_hosted
- text_injection_tests
- moonshine_check
if: always()
Expand All @@ -378,12 +396,12 @@ jobs:
echo "- validate-workflows: ${{ needs.validate-workflows.result }}" >> report.md
echo "- setup-whisper-dependencies: ${{ needs.setup-whisper-dependencies.result }}" >> report.md
echo "- security_audit: ${{ needs.security_audit.result }}" >> report.md
echo "- build_and_check: ${{ needs.build_and_check.result }}" >> report.md
echo "- unit_tests_hosted: ${{ needs.unit_tests_hosted.result }}" >> report.md
echo "- text_injection_tests: ${{ needs.text_injection_tests.result }}" >> report.md
echo "- moonshine_check: ${{ needs.moonshine_check.result }} (optional)" >> report.md
if [[ "${{ needs.setup-whisper-dependencies.result }}" != "success" ]]; then echo "::error::Setup Whisper dependencies failed."; exit 1; fi
if [[ "${{ needs.security_audit.result }}" != "success" ]]; then echo "::warning::Security audit failed - check for vulnerabilities."; fi
if [[ "${{ needs.build_and_check.result }}" != "success" ]]; then echo "::error::Build and check failed."; exit 1; fi
if [[ "${{ needs.unit_tests_hosted.result }}" != "success" ]]; then echo "::error::Build and check failed."; exit 1; fi
if [[ "${{ needs.text_injection_tests.result }}" != "success" ]]; then echo "::error::Text injection tests failed."; exit 1; fi
if [[ "${{ needs.moonshine_check.result }}" != "success" ]]; then echo "::warning::Moonshine check failed (optional)."; fi
echo "All critical stages passed successfully."
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ flamegraph.svg
.env.local
.venv/

# AI Agent Frameworks (BMAD, Claude, etc)
.bmad/
.claude/

# Logs
logs/
*.log
Expand Down Expand Up @@ -77,4 +81,3 @@ docs/config.md
docs/install.md
docs/reference.md
docs/usage.md
.venv/
36 changes: 36 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml

- repo: https://github.com/rhysd/actionlint
rev: v1.6.26
hooks:
- id: actionlint

- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --all -- --check
language: system
types: [rust]
pass_filenames: false

- id: cargo-clippy
name: cargo clippy
entry: cargo clippy --all-targets --locked -- -D warnings
language: system
types: [rust]
pass_filenames: false

- id: uv-lock-check
name: uv lock check
entry: uv lock --check
language: system
files: ^pyproject\.toml$|^uv\.lock$
pass_filenames: false
Loading
Loading