tests: add bazel 9 testing, use latest released (not rc) for bazel (#3650)

This runs the default test jobs using the test matrix so that Bazel 9 is
better
covered by testing.

The main thing needed is setting
`--incompatible_strict_action_env=false`. This is
enabled in Bazel 9, but breaks Windows. See
https://github.com/bazel-contrib/rules_python/issues/3655 for details.

It also changes to using `N.x` instead of `N.*` for specifying the Bazel
version.
The difference is `x` matches the latest released version, while `*`
matches
the latest released _or release candidate_. Since release candidates can
have
regressions, and we have a separate job for RCs, use the latest released
version.

Along the way, mark the last_rc job as soft-fail
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index dc54ea3..2f92301 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -113,12 +113,14 @@
 
 
 matrix:
+  # Keep in sync with .bcr/presubmit.yml
   platform:
     - ubuntu2204
     - debian11
     - macos_arm64
     - windows
-  bazel: [7.*, 8.*, 9.*]
+  # Keep in sync with .bcr/presubmit.yml
+  bazel: [7.x, 8.x, 9.x]
 
 tasks:
   # Keep in sync with .bcr/presubmit.yml
@@ -187,13 +189,15 @@
     bazel: 7.x
   ubuntu:
     <<: *reusable_config
-    name: "Default: Ubuntu"
+    name: "Default: Ubuntu, Bazel {bazel}"
     platform: ubuntu2204
+    bazel: ${{ bazel }}
   ubuntu_upcoming:
     <<: *reusable_config
     name: "Default: Ubuntu, upcoming Bazel"
     platform: ubuntu2204
     bazel: last_rc
+    # This is an advisory job; doesn't block merges
     # RCs may have regressions, so don't fail our CI on them
     soft_fail:
       - exit_status: 1
@@ -250,16 +254,19 @@
 
   debian:
     <<: *reusable_config
-    name: "Default: Debian"
+    name: "Default: Debian, Bazel {bazel}"
     platform: debian11
+    bazel: ${{ bazel }}
   macos_arm64:
     <<: *reusable_config
-    name: "Default: MacOS"
+    name: "Default: MacOS, Bazel {bazel}"
     platform: macos_arm64
+    bazel: ${{ bazel }}
   windows:
     <<: *reusable_config
-    name: "Default: Windows"
+    name: "Default: Windows, Bazel {bazel}"
     platform: windows
+    bazel: ${{ bazel }}
     test_flags:
       - "--test_tag_filters=-integration-test,-fix-windows"
   rbe_min:
diff --git a/.bazelrc b/.bazelrc
index 2467657..6d7e58a 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -21,6 +21,11 @@
 # Makes Bazel 7 act more like Bazel 8
 common --incompatible_use_plus_in_repo_names
 
+# Needed to make Windows with a py_binary in data deps work. The Bazel launcher
+# is used, which falls back to finding python.exe on PATH to bootstrap.
+# See https://github.com/bazel-contrib/rules_python/issues/3655
+common --incompatible_strict_action_env=false
+
 # Windows makes use of runfiles for some rules
 build --enable_runfiles
 
diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml
index 1ad61c7..a38c6ba 100644
--- a/.bcr/presubmit.yml
+++ b/.bcr/presubmit.yml
@@ -16,7 +16,7 @@
   module_path: "examples/bzlmod"
   matrix:
     platform: ["debian11", "macos", "ubuntu2204", "windows"]
-    bazel: [7.*, 8.*, 9.*]
+    bazel: [7.x, 8.x, 9.x]
   tasks:
     run_tests:
       name: "Run test module"