diff --git a/.github/workflows/call-contributor-pr-reply.yml b/.github/workflows/call-contributor-pr-reply.yml index 48a3a6576e1..57f0a8ec85d 100644 --- a/.github/workflows/call-contributor-pr-reply.yml +++ b/.github/workflows/call-contributor-pr-reply.yml @@ -1,5 +1,5 @@ name: Send reply on a new contributor pull request -on: +on: # zizmor: ignore[dangerous-triggers] pull_request_target: types: [opened] permissions: diff --git a/.github/workflows/call-pull-request-target.yml b/.github/workflows/call-pull-request-target.yml index 142acc40eea..7ff98ae712e 100644 --- a/.github/workflows/call-pull-request-target.yml +++ b/.github/workflows/call-pull-request-target.yml @@ -1,5 +1,5 @@ name: Handle pull request events -on: +on: # zizmor: ignore[dangerous-triggers] pull_request_target: types: [opened, review_requested, labeled] permissions: diff --git a/.github/workflows/call-update-pr-spreadsheet.yml b/.github/workflows/call-update-pr-spreadsheet.yml index 91965a0b98b..d6a11192e31 100644 --- a/.github/workflows/call-update-pr-spreadsheet.yml +++ b/.github/workflows/call-update-pr-spreadsheet.yml @@ -1,5 +1,5 @@ name: Update community pull requests spreadsheet -on: +on: # zizmor: ignore[dangerous-triggers] pull_request_target: types: [assigned, unassigned, opened, closed, reopened, edited, review_requested, review_request_removed] permissions: diff --git a/.github/workflows/container_image_publish.yml b/.github/workflows/container_image_publish.yml index 469030d7544..ad101fbb8cc 100644 --- a/.github/workflows/container_image_publish.yml +++ b/.github/workflows/container_image_publish.yml @@ -28,8 +28,10 @@ jobs: steps: - name: Parse Kolibri version id: parse-version + env: + RELEASE_TAG: ${{ inputs.release-tag }} run: | - tag='${{ inputs.release-tag }}' + tag="$RELEASE_TAG" echo "kolibri_version=${tag#v}" >> "$GITHUB_OUTPUT" - name: Checkout repository uses: actions/checkout@v7.0.1 diff --git a/.github/workflows/dependency_updates.yml b/.github/workflows/dependency_updates.yml index 800b31ad1a8..0628c193bb8 100644 --- a/.github/workflows/dependency_updates.yml +++ b/.github/workflows/dependency_updates.yml @@ -86,6 +86,8 @@ jobs: with: app-id: ${{ secrets.LE_BOT_APP_ID }} private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write - name: Create Pull Request if: steps.check-commit.outputs.changed == 'true' && steps.check-build-changes.outputs.has_build_changes == 'true' uses: peter-evans/create-pull-request@v8 @@ -156,6 +158,11 @@ jobs: with: app-id: ${{ secrets.LE_BOT_APP_ID }} private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + # Pushing a change to .github/workflows/, which the prek run above can + # produce, needs the app installation's Workflows permission. + permission-workflows: write - name: Create Pull Request uses: peter-evans/create-pull-request@v8 with: diff --git a/.github/workflows/i18n-download.yml b/.github/workflows/i18n-download.yml index d56f4be30bd..46206cccaa5 100644 --- a/.github/workflows/i18n-download.yml +++ b/.github/workflows/i18n-download.yml @@ -55,6 +55,8 @@ jobs: with: app-id: ${{ secrets.LE_BOT_APP_ID }} private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write - name: Create Pull Request uses: peter-evans/create-pull-request@v8 with: diff --git a/.github/workflows/npm_publish.yml b/.github/workflows/npm_publish.yml index 5e8dd14b5ab..4fc3162d979 100644 --- a/.github/workflows/npm_publish.yml +++ b/.github/workflows/npm_publish.yml @@ -60,9 +60,11 @@ jobs: run: pnpm install --ignore-scripts --no-optional - name: Publish to npm id: publish + env: + NPM_PACKAGE: ${{ github.event.inputs.npm_package }} run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.npm_package }}" != "all" ]; then - ./scripts/npm_publish.sh "${{ github.event.inputs.npm_package }}" + if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "$NPM_PACKAGE" != "all" ]; then + ./scripts/npm_publish.sh "$NPM_PACKAGE" else ./scripts/npm_publish.sh fi diff --git a/.github/workflows/npm_version_comment.yml b/.github/workflows/npm_version_comment.yml index b30a0cabe92..163c1f1d6e4 100644 --- a/.github/workflows/npm_version_comment.yml +++ b/.github/workflows/npm_version_comment.yml @@ -1,5 +1,7 @@ name: npm Package Version Comment -on: +# On workflow_run, GITHUB_SHA is the default branch tip, so the checkout below +# gets base-repository code rather than the PR head. +on: # zizmor: ignore[dangerous-triggers] workflow_run: workflows: [npm Package Version Check] types: diff --git a/.github/workflows/platform-android-release_apk.yml b/.github/workflows/platform-android-release_apk.yml index d93318dc3c7..f9eb93784d7 100644 --- a/.github/workflows/platform-android-release_apk.yml +++ b/.github/workflows/platform-android-release_apk.yml @@ -36,4 +36,6 @@ jobs: working-directory: ${{ github.workspace }} run: uv sync --package kolibri-installer-android --extra build - name: Release APK - run: uv run python scripts/play_store_api.py release "${{ inputs.version-code }}" + env: + VERSION_CODE: ${{ inputs.version-code }} + run: uv run python scripts/play_store_api.py release "$VERSION_CODE" diff --git a/.github/workflows/platform-macos-app-build_dmg.yml b/.github/workflows/platform-macos-app-build_dmg.yml index c7997a01695..c0b810860e0 100644 --- a/.github/workflows/platform-macos-app-build_dmg.yml +++ b/.github/workflows/platform-macos-app-build_dmg.yml @@ -82,7 +82,9 @@ jobs: run: make dependencies - name: Download the whlfile from URL and install if: ${{ inputs.whl-url }} - run: make get-whl whl=${{ inputs.whl-url }} + env: + WHL_URL: ${{ inputs.whl-url }} + run: make get-whl whl="$WHL_URL" - name: Download the whlfile from artifacts if: ${{ inputs.whl-file-name }} uses: actions/download-artifact@v8 @@ -91,7 +93,9 @@ jobs: path: platforms/desktop-app/whl - name: Install WHL file from artifacts if: ${{ inputs.whl-file-name }} - run: make install-whl whl=whl/${{ inputs.whl-file-name }} + env: + WHL_FILE_NAME: ${{ inputs.whl-file-name }} + run: make install-whl whl="whl/$WHL_FILE_NAME" - name: Setup app signing certificate if: ${{ inputs.release }} run: | diff --git a/.github/workflows/platform-pi-build_img.yml b/.github/workflows/platform-pi-build_img.yml index 9b38ca0610c..1865095f44d 100644 --- a/.github/workflows/platform-pi-build_img.yml +++ b/.github/workflows/platform-pi-build_img.yml @@ -42,7 +42,9 @@ jobs: - name: Download the debfile from URL and install if: ${{ inputs.deb-url }} working-directory: platforms/raspberry-pi - run: make get-deb deb=${{ inputs.deb-url }} + env: + DEB_URL: ${{ inputs.deb-url }} + run: make get-deb deb="$DEB_URL" - name: Download the debfile from artifacts if: ${{ inputs.deb-file-name }} uses: actions/download-artifact@v8 diff --git a/.github/workflows/platform-windows-app-build_exe.yml b/.github/workflows/platform-windows-app-build_exe.yml index 9a6b56eb1c6..dc50298f5fa 100644 --- a/.github/workflows/platform-windows-app-build_exe.yml +++ b/.github/workflows/platform-windows-app-build_exe.yml @@ -75,7 +75,10 @@ jobs: run: choco install wget --no-progress && choco install innosetup --version=6.6.1 --allow-downgrade --no-progress - name: Download and install the whl from URL if: ${{ inputs.whl-url }} - run: make get-whl whl=${{ inputs.whl-url }} + shell: pwsh + env: + WHL_URL: ${{ inputs.whl-url }} + run: make get-whl "whl=$env:WHL_URL" - name: Download the whl from artifacts if: ${{ inputs.whl-file-name }} uses: actions/download-artifact@v8 @@ -84,7 +87,10 @@ jobs: path: platforms/desktop-app/whl - name: Install whl from artifacts if: ${{ inputs.whl-file-name }} - run: make install-whl whl=whl/${{ inputs.whl-file-name }} + shell: pwsh + env: + WHL_FILE_NAME: ${{ inputs.whl-file-name }} + run: make install-whl "whl=whl/$env:WHL_FILE_NAME" - name: Build the application with PyInstaller run: make pyinstaller - name: Build the Windows installer diff --git a/.github/workflows/pr_build_comment.yml b/.github/workflows/pr_build_comment.yml index 68f6494e0a5..ae8e49b7f77 100644 --- a/.github/workflows/pr_build_comment.yml +++ b/.github/workflows/pr_build_comment.yml @@ -1,5 +1,7 @@ name: Build Asset Comment for Pull Request -on: +# On workflow_run, GITHUB_SHA is the default branch tip, so the checkout below +# gets base-repository code rather than the PR head. +on: # zizmor: ignore[dangerous-triggers] workflow_run: workflows: [Kolibri Build Assets for Pull Request] types: diff --git a/.github/workflows/pr_labels.yml b/.github/workflows/pr_labels.yml index 3f8e67ee95a..3e680fd907e 100644 --- a/.github/workflows/pr_labels.yml +++ b/.github/workflows/pr_labels.yml @@ -1,12 +1,14 @@ name: PR Labels -on: [pull_request_target] +on: [pull_request_target] # zizmor: ignore[dangerous-triggers] permissions: contents: read - pull-requests: write jobs: size-labels: runs-on: ubuntu-latest name: Label the PR size + permissions: + contents: read + pull-requests: write steps: - uses: codelytv/pr-size-labeler@v1 with: diff --git a/.github/workflows/pypi_packages_publish.yml b/.github/workflows/pypi_packages_publish.yml index bdda1550b24..bd8a330f375 100644 --- a/.github/workflows/pypi_packages_publish.yml +++ b/.github/workflows/pypi_packages_publish.yml @@ -62,9 +62,11 @@ jobs: run: pnpm install --frozen-lockfile - name: Publish id: publish + env: + PYPI_PACKAGE: ${{ github.event.inputs.pypi_package }} run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.pypi_package }}" != "all" ]; then - ./scripts/pypi_publish.sh "${{ github.event.inputs.pypi_package }}" + if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "$PYPI_PACKAGE" != "all" ]; then + ./scripts/pypi_publish.sh "$PYPI_PACKAGE" else ./scripts/pypi_publish.sh fi diff --git a/.github/workflows/release_kolibri.yml b/.github/workflows/release_kolibri.yml index 6062b9736ce..3d30b1e8082 100644 --- a/.github/workflows/release_kolibri.yml +++ b/.github/workflows/release_kolibri.yml @@ -3,8 +3,7 @@ on: release: types: [published] permissions: - contents: write - packages: write + contents: read jobs: latest_release: name: Check if this release is the latest release @@ -15,6 +14,8 @@ jobs: - name: Check if the current release is the latest Kolibri release id: is_latest_release uses: actions/github-script@v9 + env: + RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} with: result-encoding: string script: | @@ -23,19 +24,23 @@ jobs: repo: 'kolibri', }); - return latestRelease.tag_name === '${{ github.event.release.tag_name }}'; + return latestRelease.tag_name === process.env.RELEASE_TAG_NAME; whl: name: Build WHL file uses: ./.github/workflows/build_whl.yml upload_whl: uses: ./.github/workflows/upload_github_release_asset.yml needs: whl + permissions: + contents: write with: filename: ${{ needs.whl.outputs.whl-file-name }} release_id: ${{ github.event.release.id }} upload_tar: uses: ./.github/workflows/upload_github_release_asset.yml needs: whl + permissions: + contents: write with: filename: ${{ needs.whl.outputs.tar-file-name }} release_id: ${{ github.event.release.id }} @@ -48,6 +53,8 @@ jobs: upload_pex: uses: ./.github/workflows/upload_github_release_asset.yml needs: pex + permissions: + contents: write with: filename: ${{ needs.pex.outputs.pex-file-name }} release_id: ${{ github.event.release.id }} @@ -68,6 +75,8 @@ jobs: upload_dmg: uses: ./.github/workflows/upload_github_release_asset.yml needs: dmg + permissions: + contents: write with: filename: ${{ needs.dmg.outputs.dmg-file-name }} release_id: ${{ github.event.release.id }} @@ -81,6 +90,8 @@ jobs: upload_deb: uses: ./.github/workflows/upload_github_release_asset.yml needs: deb + permissions: + contents: write with: filename: ${{ needs.deb.outputs.deb-file-name }} release_id: ${{ github.event.release.id }} @@ -101,6 +112,8 @@ jobs: upload_exe: uses: ./.github/workflows/upload_github_release_asset.yml needs: exe + permissions: + contents: write with: filename: ${{ needs.exe.outputs.exe-file-name }} release_id: ${{ github.event.release.id }} @@ -114,6 +127,8 @@ jobs: upload_zip: uses: ./.github/workflows/upload_github_release_asset.yml needs: zip + permissions: + contents: write with: filename: ${{ needs.zip.outputs.zip-file-name }} release_id: ${{ github.event.release.id }} @@ -132,6 +147,8 @@ jobs: upload_apk: uses: ./.github/workflows/upload_github_release_asset.yml needs: apk + permissions: + contents: write with: filename: ${{ needs.apk.outputs.apk-file-name }} release_id: ${{ github.event.release.id }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/security_scan.yml similarity index 77% rename from .github/workflows/codeql.yml rename to .github/workflows/security_scan.yml index d59ba3b9340..2e3d704599a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/security_scan.yml @@ -1,15 +1,4 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL Advanced" +name: Security Scan on: push: branches: ["develop", "release-v*"] @@ -21,16 +10,18 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: - # required for all workflows - security-events: write - # required to fetch internal or private CodeQL packs - packages: read - # only required for workflows in private repositories - actions: read contents: read jobs: analyze: name: Analyze (${{ matrix.language }}) + permissions: + # required for all workflows + security-events: write + # required to fetch internal or private CodeQL packs + packages: read + # only required for workflows in private repositories + actions: read + contents: read # Runner size impacts CodeQL analysis time. To learn more, please see: # - https://gh.io/recommended-hardware-resources-for-running-codeql # - https://gh.io/supported-runners-and-hardware-resources @@ -74,3 +65,20 @@ jobs: uses: github/codeql-action/analyze@v4.37.3 with: category: "/language:${{matrix.language}}" + # Five zizmor audits need a GitHub API token and so cannot run in the prek + # hook. One of them, known-vulnerable-actions, reads the GitHub Advisories + # database, so this job's findings change without the tree changing. + zizmor: + name: Audit workflows with zizmor + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v7.0.1 + with: + persist-credentials: false + - uses: zizmorcore/zizmor-action@v0.6.2 + with: + min-confidence: medium diff --git a/.github/workflows/update_contributors.yml b/.github/workflows/update_contributors.yml index ed9a7989ef0..cf9c91ceff9 100644 --- a/.github/workflows/update_contributors.yml +++ b/.github/workflows/update_contributors.yml @@ -22,6 +22,8 @@ jobs: with: app-id: ${{ secrets.LE_BOT_APP_ID }} private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write - uses: peter-evans/create-pull-request@v8 with: token: ${{ steps.token.outputs.token }} diff --git a/.github/workflows/upload_github_release_asset.yml b/.github/workflows/upload_github_release_asset.yml index 34c3016a4aa..6b8fae1b360 100644 --- a/.github/workflows/upload_github_release_asset.yml +++ b/.github/workflows/upload_github_release_asset.yml @@ -22,7 +22,10 @@ jobs: name: ${{ inputs.filename }} path: dist - uses: actions/github-script@v9 + env: + ASSET_FILENAME: ${{ inputs.filename }} + RELEASE_ID: ${{ inputs.release_id }} with: script: | const utils = require('./.github/githubUtils.js') - await utils.uploadReleaseAsset(github, context, 'dist/${{ inputs.filename }}', '${{ inputs.release_id }}') + await utils.uploadReleaseAsset(github, context, `dist/${process.env.ASSET_FILENAME}`, process.env.RELEASE_ID) diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 00000000000..31c988992af --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,8 @@ +rules: + unpinned-uses: + config: + policies: + '*': ref-pin +# `--min-confidence medium`, passed by both callers, defers 92 findings as of +# this commit: 54 artipacked, 20 cache-poisoning, 18 informational +# template-injection. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 63f0ba23b12..f29e426e08f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,6 +31,11 @@ repos: rev: v1.7.12 hooks: - id: actionlint + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.29.0 + hooks: + - id: zizmor + args: [--no-progress, --offline, --min-confidence, medium] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.16.1 hooks: