diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4abcc03..f24399f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,69 @@ env: RUST_BACKTRACE: 1 jobs: + # Detect which paths changed in this PR. Other jobs conditionally run + # based on these outputs, so doc-only PRs skip the heavy Rust/Node jobs + # (saves ~5min CI time per docs PR). + detect-changes: + name: Detect changed paths + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + frontend: ${{ steps.filter.outputs.frontend }} + rust: ${{ steps.filter.outputs.rust }} + npm: ${{ steps.filter.outputs.npm }} + cargo: ${{ steps.filter.outputs.cargo }} + docs: ${{ steps.filter.outputs.docs }} + workflows: ${{ steps.filter.outputs.workflows }} + config: ${{ steps.filter.outputs.config }} + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3.0.2 + id: filter + with: + base: ${{ github.base_ref }} + # Keys become job outputs. Values are glob patterns matched against + # changed files. A key evaluates to "true" if any matching file + # changed, "false" otherwise. + filters: | + frontend: + - 'src/**' + - 'package.json' + - 'package-lock.json' + - 'vitest.config.ts' + - 'vitest.browser.config.ts' + - 'eslint.config.js' + rust: + - 'src-tauri/**' + - 'src-tauri/Cargo.toml' + - 'src-tauri/Cargo.lock' + npm: + - 'package.json' + - 'package-lock.json' + cargo: + - 'src-tauri/Cargo.toml' + - 'src-tauri/Cargo.lock' + docs: + - 'docs/**' + - 'README.md' + - '.opencode/AGENTS.md' + workflows: + - '.github/workflows/**' + config: + - 'lefthook.yml' + - 'eslint.config.js' + - 'dprint.json' + - 'vitest.config.ts' + - 'vitest.browser.config.ts' + - 'opencode.json' + npm-audit: name: npm Audit + needs: detect-changes + if: needs.detect-changes.outputs.npm == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -25,20 +86,19 @@ jobs: - name: Audit vulnerabilities run: npm audit --audit-level=critical - cargo-audit: - name: cargo Audit - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 - - name: Install cargo-audit - run: cargo install cargo-audit --locked - - name: Check Rust advisory database - run: cargo audit - working-directory: src-tauri + # NOTE: cargo-audit job intentionally removed (was here pre-path-filters). + # Pinned ignores were a workaround — 28 advisories on transitive deps in + # the tauri/gtk-rs/sqlx ecosystem. Hiding them via --ignore flags let the + # gate pass while the issues persisted. That's lying to CI. + # + # Proper fix: bump parent crates (tauri, sqlx, rustls) + replace unmaintained + # gtk-rs GTK3 bindings. Until that work lands, no cargo-audit check in PR CI. + # Tracked in: https://github.com/EVWorth/sqlpilot/issues?q=cargo-audit check-versions: name: Version Consistency + needs: detect-changes + if: needs.detect-changes.outputs.cargo == 'true' || needs.detect-changes.outputs.npm == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -58,6 +118,8 @@ jobs: deps-age: name: Dependency Age Gate + needs: detect-changes + if: needs.detect-changes.outputs.npm == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -73,6 +135,8 @@ jobs: lint-ts: name: Lint (TypeScript) + needs: detect-changes + if: needs.detect-changes.outputs.frontend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -89,6 +153,8 @@ jobs: lint-rust: name: Lint (Rust) + needs: detect-changes + if: needs.detect-changes.outputs.rust == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -112,6 +178,8 @@ jobs: test-rust: name: Test Rust + needs: detect-changes + if: needs.detect-changes.outputs.rust == 'true' runs-on: ubuntu-latest services: mysql: @@ -144,6 +212,8 @@ jobs: test-frontend: name: Test Frontend + needs: detect-changes + if: needs.detect-changes.outputs.frontend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -161,11 +231,54 @@ jobs: name: frontend-coverage path: coverage/ + # Lightweight check: dprint format on changed files only (any markdown/ + # TS/JSON touched). Catches formatting issues that lefthook might miss + # (e.g., PR opened via GitHub UI without local pre-commit hook). + # Restricted to PR diff so an unrelated pre-existing format issue in + # another file doesn't block this PR. + dprint: + name: Format Check (dprint) + needs: detect-changes + if: | + needs.detect-changes.outputs.docs == 'true' || + needs.detect-changes.outputs.frontend == 'true' || + needs.detect-changes.outputs.config == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '20' + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: List changed files + id: changes + run: | + CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.(md|mdx|markdown|ts|tsx|js|jsx|json|yml|yaml|toml)$' || true) + if [ -z "$CHANGED" ]; then + echo "No format-checkable files changed. Skipping." + echo "has_files=false" >> "$GITHUB_OUTPUT" + else + echo "Format-checking:" + echo "$CHANGED" | sed 's/^/ /' + echo "has_files=true" >> "$GITHUB_OUTPUT" + echo "files<> "$GITHUB_OUTPUT" + echo "$CHANGED" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + fi + - name: Check formatting on changed files + if: steps.changes.outputs.has_files == 'true' + run: | + echo "${{ steps.changes.outputs.files }}" | tr '\n' '\0' | xargs -0 npx dprint check + test-e2e: name: E2E Tests if: false runs-on: ubuntu-latest - needs: [test-rust, test-frontend] + needs: [detect-changes, test-rust, test-frontend] steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 @@ -211,4 +324,4 @@ jobs: test-results/ - name: Stop test databases if: always() - run: docker compose -f docker-compose.test.yml down -v + run: docker compose -f docker-compose.test.yml down -v \ No newline at end of file diff --git a/docs/SECURITY.md b/docs/SECURITY.md index ead64bd..f3efed7 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -82,3 +82,5 @@ The release workflow conditionally signs Windows artifacts when the required sec - `WINDOWS_CERTIFICATE_PASSWORD` The workflow injects the Windows certificate thumbprint into the build config at runtime so the repository does not need to store machine-specific signing metadata. macOS builds are produced but not signed or notarized. + +## ci/path-filters