This is an automated email from the ASF dual-hosted git repository. thepatrykk pushed a commit to branch ci/self-hosted-gcp-runners in repository https://gitbox.apache.org/repos/asf/iggy.git
commit a431e8abe87a41f467f4e3aab8b177ec478b3c22 Author: Patryk Huzarski <[email protected]> AuthorDate: Thu Aug 20 14:47:26 2026 +0200 ci: isolate Cloud Run runner pilot --- .github/runner/cloud-run/.dockerignore | 3 + .github/runner/cloud-run/Dockerfile | 54 ++++++ .github/runner/cloud-run/README.md | 278 +++++++++++++++++++++++++++ .github/runner/cloud-run/start.sh | 144 ++++++++++++++ .github/workflows/_test.yml | 14 +- .github/workflows/cloud-run-runner-pilot.yml | 113 +++++++++++ 6 files changed, 593 insertions(+), 13 deletions(-) diff --git a/.github/runner/cloud-run/.dockerignore b/.github/runner/cloud-run/.dockerignore new file mode 100644 index 000000000..38029a80d --- /dev/null +++ b/.github/runner/cloud-run/.dockerignore @@ -0,0 +1,3 @@ +* +!Dockerfile +!start.sh diff --git a/.github/runner/cloud-run/Dockerfile b/.github/runner/cloud-run/Dockerfile new file mode 100644 index 000000000..60bb396f9 --- /dev/null +++ b/.github/runner/cloud-run/Dockerfile @@ -0,0 +1,54 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +ARG RUNNER_PLATFORM=linux/amd64 + +FROM --platform=${RUNNER_PLATFORM} docker.io/library/rust@sha256:39f68a3e8e3ff425f8945ffa91128e60ff930d53e17fbb5214e95824bdd46f1b AS rust-toolchain + +RUN rustup component add clippy rustfmt --toolchain 1.97.1 + +FROM --platform=${RUNNER_PLATFORM} ghcr.io/actions/actions-runner@sha256:a1919047b038c38871d667c58cfdc7a878452711ab1212fb6036188f27a7ab16 + +USER root + +ENV CARGO_HOME=/home/runner/.cargo +ENV RUSTUP_HOME=/usr/local/rustup +ENV RUSTUP_TOOLCHAIN=1.97.1-x86_64-unknown-linux-gnu +ENV PATH=/usr/local/cargo/bin:${PATH} + +COPY --from=rust-toolchain /usr/local/cargo /usr/local/cargo +COPY --from=rust-toolchain /usr/local/rustup /usr/local/rustup +COPY start.sh /usr/local/bin/iggy-cloud-runner-start + +RUN chmod 0555 /usr/local/bin/iggy-cloud-runner-start \ + && mkdir -p /home/runner/.cargo \ + && chown runner:runner /home/runner/.cargo \ + && gpasswd --delete runner sudo \ + && gpasswd --delete runner docker \ + && rm -f /usr/bin/docker \ + /usr/bin/sudo \ + /usr/local/lib/docker/cli-plugins/docker-buildx \ + && command -v curl \ + && command -v jq \ + && command -v tail \ + && rustc --version \ + && cargo --version \ + && rustfmt --version + +USER runner + +ENTRYPOINT ["/usr/local/bin/iggy-cloud-runner-start"] diff --git a/.github/runner/cloud-run/README.md b/.github/runner/cloud-run/README.md new file mode 100644 index 000000000..ca3a4241b --- /dev/null +++ b/.github/runner/cloud-run/README.md @@ -0,0 +1,278 @@ +# Cloud Run runner pilot + +This directory contains a narrow experiment for one Apache Iggy GitHub Actions +job on a Cloud Run worker pool. It is not a replacement for the existing +pre-merge workflows. + +## Scope + +The pilot runs `cargo fmt --all -- --check` and `cargo fetch --locked` on two +runners for comparison: + +- one ephemeral Cloud Run runner; +- one GitHub-hosted `ubuntu-latest` runner. + +The workflow runs only on an upstream push to +`ci/self-hosted-gcp-runners`. It has read-only repository permissions and is not +triggered by pull requests. Both jobs also require the repository +variable `IGGY_CLOUD_RUNNER_PILOT_ENABLED` to equal `true`; an absent variable +keeps it skipped while the workflow and runner-group restrictions are being +reviewed. Do not make it a required check. + +The Cloud Run image does not provide Docker, privileged mode, `sudo`, or the +GitHub-hosted runner tool cache. Do not route BDD, testcontainers, Buildx, +`kind`, publish, or release jobs to this runner. + +## Security boundary + +Apache Infra must create an organization runner group named +`iggy-cloud-run-pilot` and restrict it to: + +- the `apache/iggy` repository; +- `apache/iggy/.github/workflows/cloud-run-runner-pilot.yml@refs/heads/ci/self-hosted-gcp-runners`. + +The Cloud Run worker pool must be configured with one instance for the pilot. + +The runner registers with the custom label `iggy-cloud-run-x64`. The workflow +requires both the group and label, so a generic `self-hosted` runner cannot pick +up the job accidentally. + +The initial test uses a short-lived organization registration token issued by +Apache Infra. It is stored in a dedicated Secret Manager secret, removed from +the runner process environment before the job starts, and used to register an +ephemeral one-job runner. Never use a classic or personal PAT here. + +Use a dedicated GCP sandbox project. The runtime service account must have no +project-level role, no VPC connector, no production access, and no service +account impersonation permission. Grant it access only to the single temporary +registration-token secret. Cloud Run captures container stdout and stderr +without granting the workload service account a project-level logging role. + +The worker can use its metadata identity during a job, so unsetting the token +environment variable is not the complete security boundary. After the runner +appears online and before pushing the pilot branch, destroy the exact one-time +secret version and remove the runtime service account's direct access to the +secret. Do not proceed unless Secret Manager reports the version as +`DESTROYED`. This remains effective even if broader IAM accidentally grants the +service account read access to the secret container. + +## Why the first test does not autoscale + +GitHub registration tokens expire after about one hour. A token supplied once +by Infra is sufficient for a fixed, one-shot pilot, but not for a pool that +creates new instances continuously. + +Apache Beam solves continuous registration with a GitHub App and a GCP Cloud +Function that exchanges an App installation token for a fresh organization +runner registration token. Its newer Actions Runner Controller deployment also +uses GitHub App credentials. Iggy should reuse an Infra-approved version of +that pattern or an Infra-managed token broker before enabling autoscaling. + +CREMA is intentionally excluded from this pilot. Its GitHub runner scaler has +an open scale-down issue where queued work can become zero while a job is still +in progress, allowing the worker pool to terminate the active runner. A fixed +single instance keeps that variable out of the first experiment. + +## Continuous registration design + +The image also supports a renewable JIT broker mode for later scale-to-zero. +Set `RUNNER_JIT_CONFIG_BROKER_URL` and +`RUNNER_JIT_CONFIG_BROKER_AUDIENCE` instead of +`RUNNER_REGISTRATION_TOKEN`. At startup the container obtains a Google-signed +identity token from the metadata server, calls the HTTPS broker, and expects a +JSON response containing a non-empty `encoded_jit_config`. It then starts the +runner with `run.sh --jitconfig`. + +The broker is a separate control-plane service. It must: + +- accept invocations only from the dedicated worker service account; +- use an ASF-installed GitHub App with organization `Self-hosted runners: write`; +- call GitHub's `generate-jitconfig` endpoint with the fixed Iggy runner group, + label, and `_work` directory; +- ignore any client-supplied organization, runner group, labels, or repository; +- return only `{ "encoded_jit_config": "..." }` and never return an App key, + installation token, or registration token; +- atomically lease one allowlisted queued `workflow_job` for each JIT config, + limit issuance to one outstanding config per lease, and reject calls when no + eligible lease exists; +- rate-limit and audit issuance without logging credentials. + +Do not grant the worker service account Secret Manager access in broker mode. +Its only additional permission is invocation of that one broker service. The +pilot remains trusted-push-only because job code inherits the worker identity +and could otherwise invoke the broker itself. + +Broker mode is not an authorization boundary for untrusted jobs. Rate limiting +alone does not prevent job code from minting another runner. Public pull +requests must remain GitHub-hosted. Supporting untrusted jobs would require a +separate controller identity to pre-authorize each queued job and a worker that +cannot independently mint another JIT config. + +The broker solves runner registration, not CREMA authentication. The scaler +needs a separate service account and renewable GitHub Actions read access. Do +not reuse the worker identity or the broker's GitHub App private key in CREMA. + +## Image contents + +The image is Linux x86-64 only. Its base images are pinned by platform digest: + +- GitHub Actions runner `2.336.0`; +- Rust `1.97.1`, matching `rust-toolchain.toml`. + +Runner auto-update and Rust channel synchronization are disabled. The workflow +fails before formatting if `rust-toolchain.toml` no longer matches the image. +Update both digests and `RUSTUP_TOOLCHAIN` deliberately when either version +changes. + +## One-shot test procedure + +The commands below are an operator runbook, not an automated deployment. Pass +`--project` and `--region` on every command instead of changing the active +`gcloud` context. + +First keep `IGGY_CLOUD_RUNNER_PILOT_ENABLED` absent or set it to `false`, then +push this gated workflow. Both jobs must be skipped. This makes the exact +workflow path and branch available for Apache Infra to review and add to the +runner-group allowlist without queueing work for a runner that does not exist. + +Set local identifiers: + +```bash +PROJECT_ID="replace-with-pmc-sandbox-project" +REGION="us-central1" +AR_REPOSITORY="iggy-ci-pilot" +WORKER_POOL="iggy-cloud-run-pilot" +RUNTIME_SERVICE_ACCOUNT="iggy-runner-runtime@${PROJECT_ID}.iam.gserviceaccount.com" +TOKEN_SECRET="iggy-runner-registration-token" +IMAGE_URI="${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPOSITORY}/runner" +``` + +Build the pinned image from the repository root: + +```bash +gcloud builds submit .github/runner/cloud-run \ + --project "$PROJECT_ID" \ + --region "$REGION" \ + --tag "${IMAGE_URI}:pilot" + +IMAGE_DIGEST="$(gcloud artifacts docker images describe "${IMAGE_URI}:pilot" \ + --project "$PROJECT_ID" \ + --format='value(image_summary.digest)')" +test -n "$IMAGE_DIGEST" +``` + +Create the dedicated secret and grant the runtime identity access only to that +secret: + +```bash +gcloud secrets create "$TOKEN_SECRET" \ + --project "$PROJECT_ID" \ + --replication-policy automatic + +gcloud secrets add-iam-policy-binding "$TOKEN_SECRET" \ + --project "$PROJECT_ID" \ + --member "serviceAccount:${RUNTIME_SERVICE_ACCOUNT}" \ + --role roles/secretmanager.secretAccessor +``` + +Add the token supplied by Infra without placing it in shell history: + +```bash +read -rsp "Runner registration token: " RUNNER_REGISTRATION_TOKEN +printf '%s' "$RUNNER_REGISTRATION_TOKEN" | gcloud secrets versions add "$TOKEN_SECRET" \ + --project "$PROJECT_ID" \ + --data-file=- +unset RUNNER_REGISTRATION_TOKEN +``` + +Deploy exactly one instance by immutable image digest: + +```bash +TOKEN_VERSION="replace-with-created-secret-version" +gcloud run worker-pools deploy "$WORKER_POOL" \ + --project "$PROJECT_ID" \ + --region "$REGION" \ + --image "${IMAGE_URI}@${IMAGE_DIGEST}" \ + --instances 1 \ + --cpu 4 \ + --memory 8Gi \ + --service-account "$RUNTIME_SERVICE_ACCOUNT" \ + --set-secrets "RUNNER_REGISTRATION_TOKEN=${TOKEN_SECRET}:${TOKEN_VERSION}" +``` + +After the runner is online, destroy the one-time token version and revoke the +runtime identity's direct access before enabling or triggering the pilot: + +```bash +gcloud secrets versions destroy "$TOKEN_VERSION" \ + --project "$PROJECT_ID" \ + --secret "$TOKEN_SECRET" + +gcloud secrets remove-iam-policy-binding "$TOKEN_SECRET" \ + --project "$PROJECT_ID" \ + --member "serviceAccount:${RUNTIME_SERVICE_ACCOUNT}" \ + --role roles/secretmanager.secretAccessor + +test "$(gcloud secrets versions describe "$TOKEN_VERSION" \ + --project "$PROJECT_ID" \ + --secret "$TOKEN_SECRET" \ + --format 'value(state)')" = "DESTROYED" +``` + +Set `IGGY_CLOUD_RUNNER_PILOT_ENABLED=true` only after Apache Infra confirms the +group restriction and the command above proves the one-time credential no +longer exists. Trigger the workflow with a new push to the pilot branch. Scale +the pool to zero as soon as the single job finishes: + +```bash +gcloud run worker-pools update "$WORKER_POOL" \ + --project "$PROJECT_ID" \ + --region "$REGION" \ + --instances 0 +``` + +After the ephemeral runner exits, the entrypoint deliberately keeps the +container idle instead of registering another runner. The pool still incurs +cost until it is scaled to zero, so prompt scale-down is mandatory. + +## Acceptance criteria + +The first pilot passes only when all of the following are true: + +1. Apache Infra confirms the runner group and workflow restriction. +2. The Cloud Run job and GitHub-hosted baseline check the same commit SHA. +3. The runner handles exactly one job and is automatically de-registered. +4. No pull request or other workflow can target the runner group. +5. The worker has no access to production, deployment credentials, or private + networks. +6. The exact registration-token secret version is `DESTROYED` before the + workflow is triggered. +7. Cloud Logging shows no restart, OOM, unexpected signal, or registration + secret in logs. +8. The pool is scaled to zero after the experiment. + +Compare queue time, startup time, execution time, result, peak memory, and cost. +Repeat at least 20 times before considering another non-Docker job. + +## Autoscaling gate + +Do not add CREMA or move required checks until all of these are complete: + +- Infra approves a GitHub App or token-broker lifecycle for fresh registration + or JIT configuration; +- no long-lived GitHub credential is available to job code; +- the scaler counts both queued and in-progress jobs and cannot terminate an + active job; +- at least 100 synthetic jobs complete without `lost communication`, stale + registrations, or cross-workflow scheduling; +- rollback to GitHub-hosted runners and scale-to-zero are exercised. + +Relevant references: + +- [ASF self-hosted runner policy](https://infra.apache.org/self-hosted-runners.html) +- [GitHub self-hosted runner security](https://docs.github.com/en/actions/reference/security/secure-use) +- [GitHub ephemeral runner guidance](https://docs.github.com/en/actions/reference/runners/self-hosted-runners) +- [Cloud Run GitHub runner tutorial](https://docs.cloud.google.com/run/docs/tutorials/github-runner) +- [Cloud Run runtime contract](https://docs.cloud.google.com/run/docs/container-contract) +- [Apache Beam token function](https://github.com/apache/beam/blob/master/.github/gh-actions-self-hosted-runners/helper-functions/cloud-functions/generateToken/index.js) +- [CREMA scale-down issue](https://github.com/GoogleCloudPlatform/cloud-run-external-metrics-autoscaling/issues/6) diff --git a/.github/runner/cloud-run/start.sh b/.github/runner/cloud-run/start.sh new file mode 100644 index 000000000..7fc3f2bf4 --- /dev/null +++ b/.github/runner/cloud-run/start.sh @@ -0,0 +1,144 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -Eeuo pipefail +umask 077 + +readonly github_scope_url="https://github.com/apache" +readonly runner_group="iggy-cloud-run-pilot" +readonly runner_labels="iggy-cloud-run-x64" +readonly runner_home="/home/runner" +readonly metadata_identity_url="http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity" + +if [[ -n "${RUNNER_REGISTRATION_TOKEN:-}" && -n "${RUNNER_JIT_CONFIG_BROKER_URL:-}" ]]; then + echo "Configure either RUNNER_REGISTRATION_TOKEN or RUNNER_JIT_CONFIG_BROKER_URL, not both" >&2 + exit 78 +fi + +runner_name_seed="${HOSTNAME:-cloud-run}-${RANDOM}-${RANDOM}" +runner_name_hash="$(printf '%s' "$runner_name_seed" | sha256sum)" +readonly runner_name="iggy-cloud-run-${runner_name_hash:0:12}" +unset runner_name_seed runner_name_hash + +if [[ -n "${RUNNER_JIT_CONFIG_BROKER_URL:-}" ]]; then + if [[ -z "${RUNNER_JIT_CONFIG_BROKER_AUDIENCE:-}" ]]; then + echo "RUNNER_JIT_CONFIG_BROKER_AUDIENCE is required with the broker URL" >&2 + exit 78 + fi + + if [[ "$RUNNER_JIT_CONFIG_BROKER_URL" != https://* ]]; then + echo "RUNNER_JIT_CONFIG_BROKER_URL must use HTTPS" >&2 + exit 78 + fi + + identity_token="$(curl \ + --fail \ + --get \ + --header "Metadata-Flavor: Google" \ + --max-time 10 \ + --noproxy metadata.google.internal \ + --show-error \ + --silent \ + --data-urlencode "audience=${RUNNER_JIT_CONFIG_BROKER_AUDIENCE}" \ + --data-urlencode "format=full" \ + "$metadata_identity_url")" + + request_body="$(jq --compact-output --null-input \ + --arg runner_name "$runner_name" \ + '{runner_name: $runner_name}')" + + broker_response="$(curl \ + --fail \ + --header "Authorization: Bearer ${identity_token}" \ + --header "Content-Type: application/json" \ + --max-time 20 \ + --request POST \ + --show-error \ + --silent \ + --data "$request_body" \ + "$RUNNER_JIT_CONFIG_BROKER_URL")" + + encoded_jit_config="$(jq --exit-status --raw-output \ + '.encoded_jit_config | select(type == "string" and length > 0)' \ + <<< "$broker_response")" + + unset RUNNER_JIT_CONFIG_BROKER_URL RUNNER_JIT_CONFIG_BROKER_AUDIENCE + identity_token="" + request_body="" + broker_response="" + unset identity_token request_body broker_response + + cd "$runner_home" + exec ./run.sh --jitconfig "$encoded_jit_config" +fi + +if [[ -z "${RUNNER_REGISTRATION_TOKEN:-}" ]]; then + echo "RUNNER_REGISTRATION_TOKEN or RUNNER_JIT_CONFIG_BROKER_URL is required" >&2 + exit 78 +fi + +registration_token="$RUNNER_REGISTRATION_TOKEN" +unset RUNNER_REGISTRATION_TOKEN + +cd "$runner_home" +./config.sh \ + --disableupdate \ + --ephemeral \ + --labels "$runner_labels" \ + --name "$runner_name" \ + --runnergroup "$runner_group" \ + --token "$registration_token" \ + --unattended \ + --url "$github_scope_url" \ + --work _work + +registration_token="" +unset registration_token + +shutdown_requested=false +runner_process_id="" + +forward_shutdown() { + local received_signal="$1" + + shutdown_requested=true + if [[ -n "$runner_process_id" ]]; then + kill "-${received_signal}" "$runner_process_id" 2>/dev/null || true + fi +} + +trap 'forward_shutdown TERM' TERM +trap 'forward_shutdown INT' INT + +set +e +./run.sh & +runner_process_id=$! +wait "$runner_process_id" +runner_exit_code=$? +set -e + +if [[ "$shutdown_requested" == true ]]; then + set +e + wait "$runner_process_id" 2>/dev/null + set -e + exit "$runner_exit_code" +fi + +runner_process_id="" +echo "Ephemeral runner exited with code ${runner_exit_code}; waiting for worker-pool scale-down" +exec tail -f /dev/null diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 77e83bbe6..eb0483efb 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -38,23 +38,11 @@ permissions: jobs: run: - # Select runner based on build target. Linux x86_64 tasks additionally - # route to the project's self-hosted ephemeral runners (GCP Cloud Run, - # label iggy-gcp) — but only for runs triggered by maintainers: pushes, - # manual dispatches, and PRs authored by org OWNER/MEMBER. Third-party - # fork PRs always stay on GitHub-hosted ubuntu-latest so external code - # never executes on project infrastructure (per ASF self-hosted runner - # guidance). NOTE: do not merge until the iggy-gcp runner group is live, - # or maintainer PR jobs will queue forever. + # Select runner based on build target runs-on: ${{ (inputs.task == 'build-aarch64-gnu' || inputs.task == 'build-aarch64-musl') && 'ubuntu-24.04-arm' || inputs.task == 'build-macos-aarch64' && 'macos-14' || inputs.task == 'build-windows-sdk' && 'windows-latest' || - (github.event_name == 'push' || - github.event_name == 'workflow_dispatch' || - github.event.pull_request.author_association == 'OWNER' || - github.event.pull_request.author_association == 'MEMBER') - && fromJSON('["self-hosted", "iggy-gcp"]') || 'ubuntu-latest' }} timeout-minutes: 60 diff --git a/.github/workflows/cloud-run-runner-pilot.yml b/.github/workflows/cloud-run-runner-pilot.yml new file mode 100644 index 000000000..1ffd49a7a --- /dev/null +++ b/.github/workflows/cloud-run-runner-pilot.yml @@ -0,0 +1,113 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Cloud Run runner pilot + +on: + push: + branches: + - ci/self-hosted-gcp-runners + +permissions: + contents: read + +concurrency: + group: cloud-run-runner-pilot + cancel-in-progress: false + +jobs: + cloud-run: + name: Cloud Run / Rust format and dependency fetch + if: >- + vars.IGGY_CLOUD_RUNNER_PILOT_ENABLED == 'true' && + github.repository == 'apache/iggy' && + github.ref == 'refs/heads/ci/self-hosted-gcp-runners' + runs-on: + group: iggy-cloud-run-pilot + labels: iggy-cloud-run-x64 + timeout-minutes: 20 + steps: + - name: Verify trusted invocation + shell: bash + run: | + set -euo pipefail + test "$GITHUB_REPOSITORY" = "apache/iggy" + test "$GITHUB_REF" = "refs/heads/ci/self-hosted-gcp-runners" + test -z "${RUNNER_REGISTRATION_TOKEN:-}" + test -z "${RUNNER_JIT_CONFIG_BROKER_URL:-}" + + - name: Record runner capabilities + shell: bash + run: | + set -euo pipefail + uname -a + rustc --version + cargo --version + rustfmt --version + df -h "$GITHUB_WORKSPACE" + free -h + + - name: Checkout exact revision + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Verify checkout revision + shell: bash + run: test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + + - name: Verify image toolchain matches repository + shell: bash + run: | + set -euo pipefail + test "$(sed -n 's/^channel = "\([^"]*\)"/\1/p' rust-toolchain.toml)" = "1.97.1" + + - name: Check Rust formatting + shell: bash + run: cargo fmt --all -- --check + + - name: Fetch locked Rust dependencies + shell: bash + run: cargo fetch --locked + + github-hosted-baseline: + name: GitHub-hosted / Rust format and dependency fetch + if: >- + vars.IGGY_CLOUD_RUNNER_PILOT_ENABLED == 'true' && + github.repository == 'apache/iggy' && + github.ref == 'refs/heads/ci/self-hosted-gcp-runners' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout exact revision + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Verify checkout revision + shell: bash + run: test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + + - name: Check Rust formatting + shell: bash + run: cargo fmt --all -- --check + + - name: Fetch locked Rust dependencies + shell: bash + run: cargo fetch --locked
