diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fed1bba..82a2e3d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,15 +11,15 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 40 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Install native build dependencies run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: workspaces: ./src-tauri -> target key: performance @@ -29,7 +29,7 @@ jobs: run: python3 scripts/benchmark.py - name: Upload performance evidence if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: performance-results path: test-results/performance/ @@ -52,29 +52,38 @@ jobs: env: CARGO_BUILD_TARGET: ${{ matrix.target }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Linux dependencies if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf squashfs-tools webkit2gtk-driver xvfb dbus-x11 python3-gi gir1.2-gtk-3.0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 - run: corepack enable - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable with: targets: ${{ matrix.target }} - - uses: Swatinem/rust-cache@v2 + components: rustfmt, clippy + - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: workspaces: ./src-tauri -> target key: ${{ matrix.target }} - run: yarn install --immutable - - run: yarn check && yarn lint && yarn build && yarn test + - run: yarn check && yarn lint + - name: Check Rust formatting + if: runner.os == 'Linux' + run: cargo fmt --manifest-path src-tauri/Cargo.toml --check - name: Build desktop packages - uses: tauri-apps/tauri-action@v0 + uses: tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f # v1.0.0 with: args: --target ${{ matrix.target }} -- --locked + - name: Test Rust code + run: yarn test + - name: Lint Rust code + if: runner.os == 'Linux' + run: cargo clippy --release --locked --all-targets --manifest-path src-tauri/Cargo.toml -- -D warnings - name: Fix Linux AppImage and test the packaged application if: runner.os == 'Linux' shell: bash @@ -89,7 +98,7 @@ jobs: cd src-tauri/target/${{ matrix.target }}/release/bundle/macos tar -czf "Graph.Prime_${{ matrix.target }}.app.tar.gz" "Graph Prime.app" - name: Upload verified packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: packages-${{ matrix.target }} if-no-files-found: error @@ -103,7 +112,7 @@ jobs: src-tauri/target/**/release/bundle/nsis/*.exe - name: Upload Linux test evidence if: always() && runner.os == 'Linux' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: linux-smoke-results path: test-results/ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..bd9d99d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,48 @@ +name: CodeQL + +on: + push: + branches: [dev, main] + pull_request: + branches: [dev, main] + schedule: + - cron: "17 14 * * 4" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-22.04 + timeout-minutes: 30 + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [actions, javascript-typescript, python, rust] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Install Rust build-script dependencies + if: matrix.language == 'rust' + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + - uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + if: matrix.language == 'rust' + - name: Initialize CodeQL + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + with: + languages: ${{ matrix.language }} + build-mode: none + - name: Analyze + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 + with: + category: /language:${{ matrix.language }} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 248f8d8..013122d 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -15,9 +15,9 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout Repository" - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: "Dependency Review" - uses: actions/dependency-review-action@v4 + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 with: # Fail the PR when a newly introduced dependency has this severity or higher fail-on-severity: moderate diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a5165d..55af097 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,13 +23,13 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Verify release version env: RELEASE_TAG: ${{ github.ref_name }} run: | test "$RELEASE_TAG" = "v$(node -p 'require("./package.json").version')" - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: packages-* path: packages diff --git a/.github/workflows/rust-clippy.yml b/.github/workflows/rust-clippy.yml deleted file mode 100644 index 09f2090..0000000 --- a/.github/workflows/rust-clippy.yml +++ /dev/null @@ -1,50 +0,0 @@ -# rust-clippy is a tool that runs a bunch of lints to catch common -# mistakes in your Rust code and help improve your Rust code. -# More details at https://github.com/rust-lang/rust-clippy -# and https://rust-lang.github.io/rust-clippy/ - -name: "Rust Clippy" - -on: - push: - branches: [main] - pull_request: - # The branches below must be a subset of the branches above - branches: [main] - schedule: - - cron: "17 14 * * 4" - -jobs: - rust-clippy-analyze: - name: Run rust-clippy analyzing - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Install Rust toolchain - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af #@v1 - with: - profile: minimal - toolchain: stable - components: clippy - override: true - - - name: Install required cargo - run: cargo install clippy-sarif sarif-fmt - - - name: Run rust-clippy - run: cargo clippy - --all-features - --message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt - continue-on-error: true - working-directory: src-tauri - - - name: Upload analysis results to GitHub - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: src-tauri/rust-clippy-results.sarif - wait-for-processing: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3f72a3..bbd8c67 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,12 @@ on: permissions: contents: read +concurrency: + group: test-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: build: + # Internal branches are already tested on push; fork commits need the PR run. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository uses: ./.github/workflows/build.yml diff --git a/docs/ci.md b/docs/ci.md new file mode 100644 index 0000000..5234388 --- /dev/null +++ b/docs/ci.md @@ -0,0 +1,45 @@ +# Continuous integration + +`Test` runs on pushes to internal branches. Pull requests from forks also run it; +internal pull requests skip the build because their commits were tested on push. +The merge into `dev` is tested again to verify the integrated code. A skipped PR +workflow can still appear in GitHub, but does not allocate the desktop build or +performance runners. Dependency Review runs separately on all pull requests. + +New pushes cancel obsolete Test runs for the same branch or pull request. Release +runs have a separate concurrency group and are never cancelled by Test. + +The shared build workflow packages Linux, Windows and both macOS architectures. +Tauri's `beforeBuildCommand` builds the frontend once; Rust tests run afterwards +so the embedded assets exist. Linux additionally requires Rust formatting, Clippy, +and the packaged AppImage GUI smoke test. Performance comparisons run in a separate +job and must pass before a release can upload packages. + +External actions are pinned to commit SHAs with version comments. Update the SHA +and comment together after checking the upstream release notes. + +## CodeQL + +`.github/workflows/codeql.yml` is the sole CodeQL configuration; GitHub's automatic +(default) setup is disabled. It analyzes Rust, JavaScript/TypeScript, Python and +GitHub Actions on pushes to `dev`/`main`, pull requests targeting either branch, +and weekly once the workflow reaches the default branch. Manual dispatch is also +available once the workflow is on the default branch. + +Use the standard `default` query suite for precise security findings. CodeQL +complements ESLint, Clippy and dependency review. Its PR merge analysis is +intentional and independent of the Test workflow's push-based build checks. + +Rust uses `build-mode: none` and requires Cargo and rustup. CodeQL still executes +build scripts and compiles macros through rust-analyzer; the Rust job installs +Tauri's native build-script dependencies without building desktop packages. + +Check the code-scanning tool status page for extraction errors and actual files +analyzed, not just a green job or zero alerts. The supported-language documentation +does not list `.svelte`; JavaScript/TypeScript analysis is not complete coverage of +Svelte components or Tauri IPC. No custom extractors or generated bundles are added. + +Sources: [setup types](https://docs.github.com/en/code-security/concepts/code-scanning/setup-types), +[query suites](https://docs.github.com/en/code-security/concepts/code-scanning/codeql/codeql-query-suites), +[Rust requirements](https://docs.github.com/en/code-security/reference/code-scanning/codeql/build-options-for-compiled-languages#building-rust), +[evaluating coverage](https://docs.github.com/en/code-security/tutorials/customize-code-scanning/evaluate-default-setup).