diff --git a/.github/actionlint.yml b/.github/actionlint.yml new file mode 100644 index 000000000..85ca1445a --- /dev/null +++ b/.github/actionlint.yml @@ -0,0 +1,18 @@ +self-hosted-runner: + labels: + - macos-13-xlarge, + - macos-14-xlarge + - macos-14-xlarge, + - macos-15-xlarge + - macos-15-xlarge, + - ubuntu-22.04-arm-xlarge + - ubuntu-22.04-xlarge + - ubuntu-22.04-xlarge, + - ubuntu-24.04-xlarge + - ubuntu-24.04-xlarge, + - ubuntu-latest-xlarge + - windows-2022-xlarge + - windows-2022-xlarge, + - windows-2025-xlarge + - windows-2025-xlarge, + - windows-latest-xlarge diff --git a/.github/workflows/_build_artifacts.yml b/.github/workflows/_build_artifacts.yml index 339103d9d..5aefa8576 100644 --- a/.github/workflows/_build_artifacts.yml +++ b/.github/workflows/_build_artifacts.yml @@ -151,7 +151,7 @@ jobs: fi cargo build $PROFILE -p ${{ matrix.package }} --target ${{ matrix.target }} - mv target/${{ matrix.target }}/${{ inputs.profile }}/${{ matrix.package }}.exe $ARTIFACT_PATH + mv target/${{ matrix.target }}/${{ inputs.profile }}/${{ matrix.package }}.exe "$ARTIFACT_PATH" - name: Install AzureSignTool shell: bash run: dotnet tool install --global AzureSignTool @@ -163,7 +163,7 @@ jobs: AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} - run: ../scripts/build/sign.sh $ARTIFACT_PATH + run: ../scripts/build/sign.sh "$ARTIFACT_PATH" - name: Upload Release Assets if: ${{ inputs.profile == 'release' && inputs.stage == 'release' && matrix.release_name }} shell: bash @@ -314,22 +314,22 @@ jobs: fi # Used for release artifact - cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} $BINARY_DEST_PATH - sha256sum $BINARY_DEST_PATH > $BINARY_DEST_PATH.sha256sum.txt + cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} "$BINARY_DEST_PATH" + sha256sum "$BINARY_DEST_PATH" > "$BINARY_DEST_PATH".sha256sum.txt gh release upload ${{ matrix.name.release_name }} \ ${{ env.BINARY_DEST_PATH }} \ ${{ env.BINARY_DEST_PATH }}.sha256sum.txt \ - $clobber \ + "$clobber" \ --repo ${{ github.repository }} - name: Copy binaries to Google Cloud Storage if: ${{ inputs.profile == 'release' && matrix.stage == 'release' && contains(fromJSON('["gateway", "client"]'), matrix.name.image_name) }} run: | gcloud storage cp \ - ${BINARY_DEST_PATH} \ + "$BINARY_DEST_PATH" \ gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }} gcloud storage cp \ - ${BINARY_DEST_PATH}.sha256sum.txt \ + "$BINARY_DEST_PATH".sha256sum.txt \ gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }}.sha256sum.txt - name: Set up QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 @@ -342,8 +342,8 @@ jobs: version="${{ matrix.name.version }}" MAJOR_VERSION="${version%%.*}" MAJOR_MINOR_VERSION="${version%.*}" - echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV - echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV + echo "MAJOR_VERSION=$MAJOR_VERSION" >> "$GITHUB_ENV" + echo "MAJOR_MINOR_VERSION=$MAJOR_MINOR_VERSION" >> "$GITHUB_ENV" - name: Docker meta id: meta uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 @@ -395,7 +395,7 @@ jobs: retention-days: 1 - name: Output image name id: image-name - run: echo "${{ matrix.name.image_name }}_image=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}" >> $GITHUB_OUTPUT + run: echo "${{ matrix.name.image_name }}_image=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}" >> "$GITHUB_OUTPUT" merge-docker-artifacts: name: merge-${{ matrix.image.name }} @@ -447,8 +447,8 @@ jobs: version="${{ matrix.image.version }}" MAJOR_VERSION="${version%%.*}" MAJOR_MINOR_VERSION="${version%.*}" - echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV - echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV + echo "MAJOR_VERSION=${MAJOR_VERSION}" >> "$GITHUB_ENV" + echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> "$GITHUB_ENV" - name: Docker meta id: meta uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 @@ -466,7 +466,11 @@ jobs: working-directory: /tmp/digests/${{ matrix.image.name }} run: | tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") - sources=$(printf '${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}@sha256:%s ' *) - echo "$sources" - docker buildx imagetools create $tags $sources + sources=$(printf '${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}@sha256:%s' *) + + echo "Tags: $tags" + echo "Sources: $sources" + + # shellcheck disable=SC2086 # $tags must be split by whitespace + docker buildx imagetools create $tags "$sources" docker buildx imagetools inspect "${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}" diff --git a/.github/workflows/_elixir.yml b/.github/workflows/_elixir.yml index 03840441c..2a5967556 100644 --- a/.github/workflows/_elixir.yml +++ b/.github/workflows/_elixir.yml @@ -65,10 +65,10 @@ jobs: id: plt_cache with: path: elixir/priv/plts - key: dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.erlang-version }}-${{ hashFiles('elixir/mix.lock') }} + key: dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.otp-version }}-${{ hashFiles('elixir/mix.lock') }} # This will make sure that we can incrementally build the PLT from older cache and save it under a new key restore-keys: | - dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.erlang-version }}- + dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.otp-version }}- - name: Create PLTs if: ${{ steps.plt_cache.outputs.cache-hit != 'true' }} run: mix dialyzer --plt diff --git a/.github/workflows/_integration_tests.yml b/.github/workflows/_integration_tests.yml index 4ae2e386f..1c8aed2cc 100644 --- a/.github/workflows/_integration_tests.yml +++ b/.github/workflows/_integration_tests.yml @@ -125,7 +125,7 @@ jobs: run: | set -xe - if [[ ! -z "${{ matrix.test.rust_log }}" ]]; then + if [[ -n "${{ matrix.test.rust_log }}" ]]; then export RUST_LOG="${{ matrix.test.rust_log }}" fi diff --git a/.github/workflows/_kotlin.yml b/.github/workflows/_kotlin.yml index 753009d86..c57617c49 100644 --- a/.github/workflows/_kotlin.yml +++ b/.github/workflows/_kotlin.yml @@ -112,7 +112,7 @@ jobs: FIREBASE_CREDENTIALS_PATH: firebase-credentials.json FIREBASE_APP_TESTERS: ${{ vars.FIREBASE_APP_TESTERS }} run: | - echo -n "$FIREBASE_APP_DISTRIBUTION_CREDENTIALS" > $FIREBASE_CREDENTIALS_PATH + echo -n "$FIREBASE_APP_DISTRIBUTION_CREDENTIALS" > "$FIREBASE_CREDENTIALS_PATH" ./gradlew appDistributionUploadRelease uploadCrashlyticsSymbolFileRelease build_debug: diff --git a/.github/workflows/_rust.yml b/.github/workflows/_rust.yml index f75ecf9d8..9f8856d24 100644 --- a/.github/workflows/_rust.yml +++ b/.github/workflows/_rust.yml @@ -98,16 +98,16 @@ jobs: cargo test --all-features ${{ steps.setup-rust.outputs.test-packages }} -- --include-ignored --nocapture # Poor man's test coverage testing: Grep the generated logs for specific patterns / lines. - rg --count --no-ignore SendIcmpPacket $TESTCASES_DIR - rg --count --no-ignore SendUdpPacket $TESTCASES_DIR - rg --count --no-ignore SendTcpPayload $TESTCASES_DIR - rg --count --no-ignore SendDnsQueries $TESTCASES_DIR - rg --count --no-ignore "Packet for DNS resource" $TESTCASES_DIR - rg --count --no-ignore "Packet for CIDR resource" $TESTCASES_DIR - rg --count --no-ignore "Packet for Internet resource" $TESTCASES_DIR - rg --count --no-ignore "Truncating DNS response" $TESTCASES_DIR - rg --count --no-ignore "Destination is unreachable" $TESTCASES_DIR - rg --count --no-ignore "Forwarding query for DNS resource to corresponding site" $TESTCASES_DIR + rg --count --no-ignore SendIcmpPacket "$TESTCASES_DIR" + rg --count --no-ignore SendUdpPacket "$TESTCASES_DIR" + rg --count --no-ignore SendTcpPayload "$TESTCASES_DIR" + rg --count --no-ignore SendDnsQueries "$TESTCASES_DIR" + rg --count --no-ignore "Packet for DNS resource" "$TESTCASES_DIR" + rg --count --no-ignore "Packet for CIDR resource" "$TESTCASES_DIR" + rg --count --no-ignore "Packet for Internet resource" "$TESTCASES_DIR" + rg --count --no-ignore "Truncating DNS response" "$TESTCASES_DIR" + rg --count --no-ignore "Destination is unreachable" "$TESTCASES_DIR" + rg --count --no-ignore "Forwarding query for DNS resource to corresponding site" "$TESTCASES_DIR" env: # diff --git a/.github/workflows/_static-analysis.yml b/.github/workflows/_static-analysis.yml index 7c0a13aea..68de670b0 100644 --- a/.github/workflows/_static-analysis.yml +++ b/.github/workflows/_static-analysis.yml @@ -20,7 +20,7 @@ jobs: PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} REPOSITORY_NAME: ${{ github.repository }} run: | - PR_TITLE=$(gh pr view $PULL_REQUEST_NUMBER --repo $REPOSITORY_NAME --json title -q '.title') + PR_TITLE=$(gh pr view "$PULL_REQUEST_NUMBER" --repo "$REPOSITORY_NAME" --json title -q '.title') pr_title_length=${#PR_TITLE} @@ -43,7 +43,7 @@ jobs: echo "Version manifests up to date" else # Uncommitted changes - echo '`scripts/bump-versions.sh` found outdated files! Showing diff' + echo "'scripts/bump-versions.sh' found outdated files! Showing diff" git diff exit 1 fi @@ -57,6 +57,12 @@ jobs: fail: true args: --offline --verbose --no-progress **/*.md + actionlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: raven-actions/actionlint@3a24062651993d40fed1019b58ac6fbdfbf276cc # v2.0.1 + global-linter: runs-on: ubuntu-22.04-xlarge steps: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 590a2d663..a2389068d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,14 +35,14 @@ jobs: # For workflow_dispatch or workflow_call, run all jobs if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "${{ github.event_name }}" = "workflow_call" ]; then - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" exit 0; fi # For main branch runs, run all jobs if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref_name }}" = "main" ]; then - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" exit 0; fi @@ -68,19 +68,19 @@ jobs: # Run all jobs if CI configuration changes if grep -q '^\.github/' changed_files.txt; then - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" exit 0; fi # Run all jobs if tool versions change if grep -q '^\.tool-versions' changed_files.txt; then - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" exit 0; fi # Run all jobs if docker-compose changes if grep -q '^docker-compose.yml' changed_files.txt; then - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" exit 0; fi @@ -105,7 +105,7 @@ jobs: jobs="${jobs},codeql" fi - echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT + echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT" required-check: name: required-check @@ -127,14 +127,14 @@ jobs: failed_jobs=$(echo "$jobs_json" | jq -r '[.[] | select(.conclusion == "failure")] | length') completed_jobs=$(echo "$jobs_json" | jq '[.[] | select(.status == "completed")] | length') - if [ $failed_jobs -gt 0 ]; then + if [ "$failed_jobs" -gt 0 ]; then echo "At least one job has failed." exit 1 fi echo "Completed: $completed_jobs/$total_jobs" - if [ $completed_jobs -eq $total_jobs ]; then + if [ "$completed_jobs" -eq "$total_jobs" ]; then break fi @@ -312,7 +312,7 @@ jobs: # We need to increase the log level to make sure that they don't hold off storm of packets # generated by UDP tests. Wire is especially chatty. sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,info/' docker-compose.yml - cat docker-compose.yml | grep RUST_LOG + grep RUST_LOG docker-compose.yml # Start services in the same order each time for the tests docker compose up -d iperf3 @@ -392,9 +392,10 @@ jobs: --testbed github-actions \ --file bmf.json \ --adapter json \ - --branch "${{ github.head_ref || github.ref_name }}" \ + --branch "${{ env.BRANCH }}" \ --branch-start-point "${{ github.base_ref }}" \ --github-actions ${{ secrets.GITHUB_TOKEN }} \ --ci-only-on-alert env: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }} + BRANCH: "${{ github.head_ref || github.ref_name }}" diff --git a/.github/workflows/publish-to-winget.yml b/.github/workflows/publish-to-winget.yml index fe06a8cd9..2c9276f0f 100644 --- a/.github/workflows/publish-to-winget.yml +++ b/.github/workflows/publish-to-winget.yml @@ -25,7 +25,7 @@ jobs: run: | version=${{ inputs.release_name || github.event.release.name }} version=${version#${{ matrix.tag_prefix }}-} - echo "version=$version" >> $GITHUB_OUTPUT + echo "version=$version" >> "$GITHUB_OUTPUT" shell: bash - uses: vedantmgoyal9/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # main if: ${{ startsWith((inputs.release_name || github.event.release.name), matrix.tag_prefix) }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2d641756a..25d970aa2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -63,11 +63,12 @@ jobs: sha=$(gh release view "${release_name}" --json targetCommitish -q '.targetCommitish') + # shellcheck disable=SC2129 # individual env exports are cleaner echo "artifact=$ARTIFACT" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "major_version=$MAJOR_VERSION" >> "$GITHUB_OUTPUT" echo "major_minor_version=$MAJOR_MINOR_VERSION" >> "$GITHUB_OUTPUT" - echo "sha=${sha}" >> "$GITHUB_OUTPUT" + echo "sha=$sha" >> "$GITHUB_OUTPUT" - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Pull and push @@ -101,25 +102,25 @@ jobs: for arch in "${ARCHITECTURES[@]}"; do # Copy sha256sum.txt gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/${arch}.sha256sum.txt + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/$arch.sha256sum.txt" gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/${arch}.sha256sum.txt + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/$arch.sha256sum.txt" # Copy binaries gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/${arch} + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/$arch" gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" gcloud storage cp \ - gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \ - gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/${arch} + "gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \ + "gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/$arch" done create-publish-pr: @@ -143,21 +144,22 @@ jobs: version=${version#${{ matrix.component }}-} # Configure gpg - echo "${RELEASE_PR_BOT_GPG_KEY}" | gpg --import --batch + echo "$RELEASE_PR_BOT_GPG_KEY" | gpg --import --batch GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format long "github-bot@firezone.dev" | grep sec | sed 's/.*\/\([^ ]*\).*/\1/') # Configure git git config --local user.email "github-bot@firezone.dev" git config --local user.name "Firezone Bot" - git config --local user.signingkey "${GPG_KEY_ID}" + git config --local user.signingkey "$GPG_KEY_ID" git config --local commit.gpgsign true echo "use-agent" >> ~/.gnupg/gpg.conf echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf - export GPG_TTY=$(tty) + GPG_TTY=$(tty) + export GPG_TTY # Create the PR - scripts/create-publish-pr.sh ${{ matrix.component }} $version + scripts/create-publish-pr.sh ${{ matrix.component }} "$version" shell: bash env: GITHUB_TOKEN: ${{ secrets.RELEASE_PR_BOT_GITHUB_TOKEN }} diff --git a/scripts/nix/flake.nix b/scripts/nix/flake.nix index ec4070b36..6c6f12adb 100644 --- a/scripts/nix/flake.nix +++ b/scripts/nix/flake.nix @@ -59,7 +59,7 @@ { devShells = { x86_64-linux.default = pkgs.mkShell { - packages = [ pkgs.cargo-tauri pkgs.iptables pkgs.pnpm pkgs.unstable.cargo-sort pkgs.cargo-deny pkgs.cargo-autoinherit pkgs.dump_syms pkgs.xvfb-run pkgs.ktlint ]; + packages = [ pkgs.cargo-tauri pkgs.iptables pkgs.pnpm pkgs.unstable.cargo-sort pkgs.cargo-deny pkgs.cargo-autoinherit pkgs.dump_syms pkgs.xvfb-run pkgs.ktlint pkgs.unstable.actionlint ]; buildInputs = packages; src = ../..;