diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5990d9c..1f79aa0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,14 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file - +# The previous file was GitHub's unfilled template (package-ecosystem: ""), which +# does nothing. Weekly PRs for the pinned things that otherwise go stale. version: 2 updates: - - package-ecosystem: "" # See documentation for possible values - directory: "/" # Location of package manifests + # SHA-pinned actions: Dependabot bumps the SHA and the "# vX.Y.Z" comment together. + - package-ecosystem: "github-actions" + directory: "/" schedule: interval: "weekly" + # maturin (hash-pinned). Verify the first PR keeps the --hash lines intact. + - package-ecosystem: "pip" + directory: "/environments/alpine-3.24-musl" + schedule: + interval: "weekly" \ No newline at end of file diff --git a/.github/workflows/build-environment-image.yml b/.github/workflows/build-environment-image.yml index 1112a4e..0c91cb9 100644 --- a/.github/workflows/build-environment-image.yml +++ b/.github/workflows/build-environment-image.yml @@ -133,6 +133,12 @@ jobs: aarch64) goarch=arm64; rustup_sha_var=RUSTUP_SHA256_AARCH64 ;; *) echo "::error::unknown arch $ARCH"; exit 1 ;; esac + # The runner image is a declared trust root (not pinned): record exactly what ran. + [ -n "${ImageOS:-}" ] && [ -n "${ImageVersion:-}" ] \ + || { echo "::error::ImageOS/ImageVersion not set; not a GitHub-hosted runner?"; exit 1; } + docker_version="$(docker version --format '{{.Server.Version}}')" + buildx_version="$(docker buildx version | awk '{print $2}')" + [ -n "$docker_version" ] && [ -n "$buildx_version" ] || { echo "::error::cannot read docker/buildx versions"; exit 1; } arg() { sed -n "s/^ARG $1=//p" "$CONTEXT/Containerfile"; } base="$(awk '/^FROM /{print $2; exit}' "$CONTEXT/Containerfile")" base_ref="${base%@*}" @@ -153,6 +159,11 @@ jobs: --arg assert_script_sha256 "$(sha256sum "$CONTEXT/assert-sccache-build.sh" | cut -d' ' -f1)" \ --arg requirements_sha256 "$(sha256sum "$CONTEXT/requirements-builder.txt" | cut -d' ' -f1)" \ --arg apk_lock_sha256 "$(sha256sum "$CONTEXT/apk.lock.$ARCH" | cut -d' ' -f1)" \ + --arg runner_image_os "$ImageOS" \ + --arg runner_image_version "$ImageVersion" \ + --arg runner_arch "${RUNNER_ARCH:-}" \ + --arg docker_version "$docker_version" \ + --arg buildx_version "$buildx_version" \ --arg builder_image "$IMAGE@$DIGEST" \ --arg commit "$COMMIT" \ '{base_image_ref:$base_ref, base_image_index_digest:$base_index, base_platform:$base_platform, @@ -160,6 +171,8 @@ jobs: rustup_sha256:$rustup_sha256, rust_version:$rust_version, sccache_version:$sccache_version, cargo_auditable_version:$cargo_auditable_version, assert_script_sha256:$assert_script_sha256, requirements_builder_sha256:$requirements_sha256, apk_lock_sha256:$apk_lock_sha256, + runner:{image_os:$runner_image_os, image_version:$runner_image_version, arch:$runner_arch, + docker_version:$docker_version, buildx_version:$buildx_version}, builder_image:$builder_image, source_commit:$commit}' > "builder-inputs.$ARCH.json" cat "builder-inputs.$ARCH.json" diff --git a/.github/workflows/merge-bot.yml b/.github/workflows/merge-bot.yml index 0ec18aa..a770d9a 100644 --- a/.github/workflows/merge-bot.yml +++ b/.github/workflows/merge-bot.yml @@ -136,20 +136,27 @@ jobs: - name: Wait for CodeQL checks run: | set -euo pipefail + # Required checks must exist, be completed, and conclude success. + # none/null (not created or still running) and neutral (CodeQL's + # aggregate check reports neutral while results are still being + # processed) mean "not settled yet": retry. Anything else that is + # not success is a hard fail. Timeout fails closed. for i in $(seq 1 20); do ok=1 - for name in "CodeQL" "Analyze (actions)"; do + for name in "CodeQL" "Analyze (actions)" "Analyze (python)"; do c=$(gh api "repos/$GITHUB_REPOSITORY/commits/$HEAD_SHA/check-runs?per_page=100" \ - --jq "[.check_runs[] | select(.name == \"$name\")] | sort_by(.started_at) | last | .conclusion // \"none\"") - echo "$name: $c" - if [ "$c" = "none" ] || [ "$c" = "null" ]; then ok=0 - elif [ "$c" != "success" ]; then echo "::error::$name concluded $c"; exit 1 - fi + --jq "[.check_runs[] | select(.name == \"$name\")] | sort_by(.started_at) | last | if . == null or .status != \"completed\" then \"none\" else .conclusion // \"none\" end") + echo "attempt $i: $name: $c" + case "$c" in + success) ;; + none|null|neutral) ok=0 ;; + *) echo "::error::$name concluded $c"; exit 1 ;; + esac done [ "$ok" = 1 ] && { echo "CodeQL checks green."; exit 0; } sleep 30 done - echo "::error::CodeQL produced no result in 10 min. Check that the CodeQL workflow is enabled."; exit 1 + echo "::error::CodeQL checks did not all reach success in 10 min (last state above). Check that the CodeQL workflow is enabled."; exit 1 # =============================================================== # JOB 3: Human approval gate, then fast-forward push via GitHub App @@ -191,4 +198,4 @@ jobs: # Non-force ref update: rejected unless it is a pure fast-forward. Same SHA, signatures kept. gh api -X PATCH "repos/$GITHUB_REPOSITORY/git/refs/heads/$BASE_REF" \ -f sha="$HEAD_SHA" -F force=false --jq '.object.sha' - echo "Fast-forwarded $BASE_REF to $HEAD_SHA." + echo "Fast-forwarded $BASE_REF to $HEAD_SHA." \ No newline at end of file