Skip to content

🔒 Fix: Use strict UTF-8 string conversion for database password #190

🔒 Fix: Use strict UTF-8 string conversion for database password

🔒 Fix: Use strict UTF-8 string conversion for database password #190

Workflow file for this run

# SPDX-FileCopyrightText: 2025 Knitli Inc. <knitli@knit.li>
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
#
# SPDX-License-Identifier: MIT OR Apache-2.0
# ! GitHub Action to run the CI pipeline for Thread
# ! Comprehensive CI with multi-platform testing, WASM builds, and security scanning
name: CI
on:
push:
branches:
- main
- develop
- staging
- 001-*
pull_request:
branches:
- main
- develop
- staging
workflow_dispatch:
permissions:
contents: read
env:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUSTFLAGS: -D warnings
jobs:
# Quick formatting and linting checks that fail fast
quick-checks:
name: Quick Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- run: |
sudo apt update && sudo apt install -y clang llvm-dev
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
components: rustfmt, clippy
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Check formatting
run: cargo fmt --all -- --config-path ./rustfmt.toml --check
- name: Run clippy
# thread-language's napi-* features conflict with tree-sitter at runtime;
# run it separately with only the compatible feature set.
run: |
cargo clippy --workspace --exclude thread-language --all-features --all-targets -- -D warnings
cargo clippy -p thread-language --features all-parsers,matching --all-targets -- -D warnings
- name: Check typos
uses: crate-ci/typos@v1.16.23
# Test matrix for multiple platforms and Rust versions
test:
name: Test (${{ matrix.os }}, ${{ matrix.rust }})
needs: quick-checks
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
rust:
- stable
include:
# Also test on beta and nightly on Linux
- os: ubuntu-latest
rust: beta
- os: ubuntu-latest
rust: nightly
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust ${{ matrix.rust }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-${{ matrix.rust }}
cache-on-failure: true
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Run tests (nextest)
# thread-language's napi-* features conflict with tree-sitter-parsing at runtime;
# run it separately with only the compatible feature set.
run: |
cargo nextest run --workspace --exclude thread-language --all-features --no-fail-fast
cargo nextest run -p thread-language --features all-parsers,matching --no-fail-fast
- name: Run doc tests
run: |
cargo test --doc --workspace --exclude thread-language --all-features
cargo test --doc -p thread-language --features all-parsers,matching
# Build and test WASM target for Edge deployment
wasm:
name: WASM Build & Test
needs: quick-checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
- name: Build WASM (dev)
run: cargo run -p xtask build-wasm
- name: Build WASM (release)
run: cargo run -p xtask build-wasm --release
- name: Upload WASM artifacts
uses: actions/upload-artifact@v4
with:
name: wasm-build-${{ github.sha }}
path: |
thread_wasm_bg.wasm
thread_wasm.js
thread_wasm.d.ts
retention-days: 7
# Performance benchmarks (only on main branch or manual trigger)
benchmark:
name: Benchmarks
needs: quick-checks
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Run benchmarks
run: cargo bench --workspace --no-fail-fast -- --output-format bencher | tee benchmark-results.txt
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results-${{ github.sha }}
path: benchmark-results.txt
retention-days: 30
# Security audit with cargo-audit
security_audit:
name: Security Audit
needs: quick-checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Run cargo-audit
uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
# License compliance check with REUSE
license:
name: License Compliance
needs: quick-checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v2
# Code coverage (only on main or PRs to main)
coverage:
name: Code Coverage
needs: quick-checks
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2
with:
tool: cargo-llvm-cov
- name: Generate coverage
run: |
cargo llvm-cov --no-report --workspace --exclude thread-language --all-features
cargo llvm-cov --no-report -p thread-language --features all-parsers,matching
cargo llvm-cov --no-run --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: lcov.info
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
# Integration tests with Postgres (only on main or manual)
integration:
name: Integration Tests
needs: test
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: thread_test
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Run integration tests
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/thread_test
run: cargo nextest run --manifest-path crates/flow/Cargo.toml --all-features --test integration_tests --test d1_integration_test
# Performance regression tests (on PRs and main)
performance_regression:
name: Performance Regression Tests
needs: quick-checks
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Run performance regression tests
run: |
cargo nextest run --manifest-path crates/flow/Cargo.toml \
--all-features \
--test performance_regression_tests \
--no-capture
- name: Check for regressions
if: failure()
run: |
echo "⚠️ Performance regression detected!"
echo "Review test output above for specific failures."
exit 1
# Load testing benchmarks (manual trigger or main branch only)
load_testing:
name: Load Testing Benchmarks
needs: quick-checks
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Run load test benchmarks
run: |
cargo bench --manifest-path crates/flow/Cargo.toml \
--bench load_test \
--all-features \
-- --output-format bencher | tee load-test-results.txt
- name: Upload load test results
uses: actions/upload-artifact@v4
with:
name: load-test-results-${{ github.sha }}
path: load-test-results.txt
retention-days: 90
- name: Compare with baseline (if exists)
continue-on-error: true
run: "if [ -f .benchmark-baseline/load-test-baseline.txt ]; then\n echo \"\U0001F4CA Comparing with baseline...\"\n # Simple diff for now - could enhance with criterion-compare\n diff .benchmark-baseline/load-test-baseline.txt load-test-results.txt || true\nelse\n echo \"\U0001F4DD No baseline found - this will become the baseline\"\n mkdir -p .benchmark-baseline\n cp load-test-results.txt .benchmark-baseline/load-test-baseline.txt\nfi\n"
# Final success check - all required jobs must pass
ci-success:
name: CI Success
needs:
- quick-checks
- test
- wasm
- security_audit
- license
- performance_regression
if: always()
runs-on: ubuntu-latest
steps:
- name: Check all jobs
run: |
if [[ "${{ needs.quick-checks.result }}" != "success" ]] || \
[[ "${{ needs.test.result }}" != "success" ]] || \
[[ "${{ needs.wasm.result }}" != "success" ]] || \
[[ "${{ needs.security_audit.result }}" != "success" ]] || \
[[ "${{ needs.license.result }}" != "success" ]] || \
[[ "${{ needs.performance_regression.result }}" != "success" ]]; then
echo "❌ One or more required jobs failed"
exit 1
fi
echo "✅ All required jobs passed!"