fix(admin): kill_process uses raw_sql + add integration tests (closes #261) #356
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| # Explicit types. Excluding 'closed' stops GH from re-running CI after | |
| # a PR merges or closes (when the merge closed the prior run, the | |
| # 'closed' event used to trigger a redundant 're-verify already-green | |
| # code' run). | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| # Cancel any in-flight or queued runs in this group when a new run | |
| # starts. Keyed by workflow + PR number (for PRs) or workflow + ref | |
| # (for direct branch pushes) so concurrent PRs and unrelated runs | |
| # don't trip over each other. Industry standard pattern. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| 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@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.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 | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Audit signatures (verify package integrity) | |
| run: npm audit signatures | |
| - name: Audit vulnerabilities | |
| run: npm audit --audit-level=critical | |
| # NOTE: cargo-audit runs via the cargo-audit-check wrapper script (not | |
| # raw cargo audit). The wrapper: | |
| # - Fails ONLY on real vulnerabilities (RUSTSEC type "vulnerability") | |
| # - Logs unmaintained/yanked/unsound warnings to job output without blocking | |
| # - Uses zero --ignore flags (no silencing) | |
| # | |
| # 17 transitive advisories remain (gtk-rs GTK3 bindings + glib unsound + | |
| # unic-* sub-deps) that cannot be fixed without upstream action. | |
| # Tracked in #204. | |
| cargo-audit: | |
| name: cargo Audit | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.cargo == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 | |
| - name: Install jq | |
| run: sudo apt-get install -y jq | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit --locked | |
| - name: Run audit check (vulnerabilities fail, warnings log) | |
| run: bash "$GITHUB_WORKSPACE/scripts/cargo-audit-check.sh" | |
| env: | |
| CARGO_WORKSPACE_DIR: src-tauri | |
| 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 | |
| - name: Check versions match across package.json, Cargo.toml, tauri.conf.json | |
| run: | | |
| jsver=$(node -p "require('./package.json').version") | |
| rsver=$(grep '^version' src-tauri/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') | |
| taver=$(node -p "require('./src-tauri/tauri.conf.json').version") | |
| if [ "$jsver" != "$rsver" ] || [ "$jsver" != "$taver" ]; then | |
| echo "Version mismatch!" | |
| echo " package.json: $jsver" | |
| echo " Cargo.toml: $rsver" | |
| echo " tauri.conf.json: $taver" | |
| exit 1 | |
| fi | |
| echo "All versions match: $jsver" | |
| 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 | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: TypeScript lint | |
| run: npm run lint | |
| - name: TypeScript type check | |
| run: npm run type-check | |
| 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 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 | |
| with: | |
| components: rustfmt, clippy | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| workspaces: src-tauri | |
| - name: Install system dependencies | |
| uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # v1.6.3 | |
| with: | |
| packages: libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf | |
| version: 1.0 | |
| - name: Rust format check | |
| run: cargo fmt --all -- --check | |
| working-directory: src-tauri | |
| - name: Rust clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| working-directory: src-tauri | |
| test-rust: | |
| name: Test Rust | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.rust == 'true' | |
| runs-on: ubuntu-latest | |
| services: | |
| mysql: | |
| image: mysql:8.0 | |
| env: | |
| MYSQL_ROOT_PASSWORD: test_root_password | |
| MYSQL_DATABASE: test_db | |
| MYSQL_USER: test_user | |
| MYSQL_PASSWORD: test_password | |
| ports: | |
| - 13306:3306 | |
| options: >- | |
| --health-cmd "mysqladmin ping -h localhost" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| workspaces: src-tauri | |
| - name: Seed test database | |
| run: mysql -h 127.0.0.1 -P 13306 -u root -ptest_root_password < tests/fixtures/sql/seed.sql | |
| - name: Install cargo-tarpaulin | |
| run: cargo install cargo-tarpaulin --locked | |
| - name: Run Rust tests with coverage | |
| run: cargo tarpaulin -p mas-core -p mas-export -p mas-admin --out Lcov --output-dir coverage/ | |
| working-directory: src-tauri | |
| 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 | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run unit tests | |
| run: npm run test:unit -- --coverage | |
| - name: Upload coverage artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| 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@820762786026740c76f36085b0efc47a31fe5020 # v7.0.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<<EOF" >> "$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: [detect-changes, test-rust, test-frontend] | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1.0.0 | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install system dependencies | |
| uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # v1.6.3 | |
| with: | |
| packages: libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf | |
| version: 1.0 | |
| - name: Start test databases | |
| run: docker compose -f docker-compose.test.yml up -d | |
| - name: Wait for databases | |
| run: | | |
| echo "Waiting for MySQL 8..." | |
| timeout 60 bash -c 'until docker exec mas-mysql-8 mysqladmin ping -h localhost -u root -ptest_root_password 2>/dev/null; do sleep 2; done' || echo "WARNING: MySQL 8 did not become ready" | |
| echo "Waiting for MySQL 5.7..." | |
| timeout 60 bash -c 'until docker exec mas-mysql-57 mysqladmin ping -h localhost -u root -ptest_root_password 2>/dev/null; do sleep 2; done' || echo "WARNING: MySQL 5.7 did not become ready" | |
| echo "Waiting for MariaDB..." | |
| timeout 60 bash -c 'until docker exec mas-mariadb-11 mariadb-admin ping -h localhost -u root -ptest_root_password 2>/dev/null; do sleep 2; done' || echo "WARNING: MariaDB did not become ready" | |
| echo "Database wait complete" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Install Playwright | |
| run: npx playwright install --with-deps chromium | |
| - name: Build application | |
| run: npm run build | |
| - name: Run E2E tests | |
| run: npm run test:e2e | |
| env: | |
| TEST_MYSQL8_URL: "mysql://test_user:test_password@127.0.0.1:13306/test_db" | |
| TEST_MYSQL57_URL: "mysql://test_user:test_password@127.0.0.1:13307/test_db" | |
| TEST_MARIADB_URL: "mysql://test_user:test_password@127.0.0.1:13308/test_db" | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: e2e-results | |
| path: | | |
| playwright-report/ | |
| test-results/ | |
| - name: Stop test databases | |
| if: always() | |
| run: docker compose -f docker-compose.test.yml down -v |