treewide: replace platform_transition_binary

platform_transition_binary changes the platform, but does not set
@io_bazel_rules_go//go/config:static. Instead, build_static_transition
is now used, which sets both.

A second benefit of this change is that we have fewer places where the
amd64 architecture is mentioned, which should make it easier to enable
multi-platform builds.

Change-Id: Id01e0d942a12770b8b34b0e6825f314128149b40
Reviewed-on: https://review.monogon.dev/c/monogon/+/4162
Tested-by: Jenkins CI
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
diff --git a/cloud/agent/takeover/BUILD.bazel b/cloud/agent/takeover/BUILD.bazel
index 310a82d..ee6f0ab 100644
--- a/cloud/agent/takeover/BUILD.bazel
+++ b/cloud/agent/takeover/BUILD.bazel
@@ -1,6 +1,6 @@
-load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_binary")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 load("//build/static_binary_tarball:def.bzl", "static_binary_tarball")
+load("//osbase/build:def.bzl", "build_static_target")
 load("//osbase/build/mkcpio:def.bzl", "node_initramfs")
 
 go_library(
@@ -33,10 +33,9 @@
 )
 
 # Used by e2e tests, forces a static build
-platform_transition_binary(
+build_static_target(
     name = "takeover",
-    binary = ":takeover_bin",
-    target_platform = "//build/platforms:linux_amd64_static",
+    dep = ":takeover_bin",
     visibility = ["//visibility:public"],
 )
 
diff --git a/metropolis/cli/takeover/BUILD.bazel b/metropolis/cli/takeover/BUILD.bazel
index c0b16f4..ca6e625 100644
--- a/metropolis/cli/takeover/BUILD.bazel
+++ b/metropolis/cli/takeover/BUILD.bazel
@@ -1,5 +1,5 @@
-load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_binary")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+load("//osbase/build:def.bzl", "build_static_target")
 load("//osbase/build/mkcpio:def.bzl", "node_initramfs")
 
 node_initramfs(
@@ -57,9 +57,8 @@
     visibility = ["//visibility:public"],
 )
 
-platform_transition_binary(
+build_static_target(
     name = "takeover",
-    binary = ":takeover_bin",
-    target_platform = "//build/platforms:linux_amd64_static",
+    dep = ":takeover_bin",
     visibility = ["//visibility:public"],
 )
diff --git a/metropolis/test/e2e/connectivity/agent/BUILD.bazel b/metropolis/test/e2e/connectivity/agent/BUILD.bazel
index cb52497..b9db83c 100644
--- a/metropolis/test/e2e/connectivity/agent/BUILD.bazel
+++ b/metropolis/test/e2e/connectivity/agent/BUILD.bazel
@@ -1,7 +1,6 @@
-load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_binary")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 load("@rules_oci//oci:defs.bzl", "oci_image")
-load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
+load("//build/static_binary_tarball:def.bzl", "static_binary_tarball")
 
 go_library(
     name = "agent_lib",
@@ -20,23 +19,16 @@
     visibility = ["//visibility:private"],
 )
 
-platform_transition_binary(
-    name = "agent_transitioned",
-    binary = ":agent",
-    target_platform = "//build/platforms:linux_amd64_static",
-    visibility = ["//visibility:private"],
-)
-
-pkg_tar(
+static_binary_tarball(
     name = "agent_layer",
-    srcs = [":agent_transitioned"],
+    executable = ":agent",
     visibility = ["//visibility:private"],
 )
 
 oci_image(
     name = "agent_image",
     base = "@distroless_base",
-    entrypoint = ["/agent"],
+    entrypoint = ["/app/metropolis/test/e2e/connectivity/agent/agent_/agent"],
     tars = [":agent_layer"],
     visibility = ["//metropolis/test/e2e:__pkg__"],
     workdir = "/app",
diff --git a/osbase/build/def.bzl b/osbase/build/def.bzl
index 7a6fbd7..f1665b5 100644
--- a/osbase/build/def.bzl
+++ b/osbase/build/def.bzl
@@ -1,3 +1,5 @@
+load("@bazel_skylib//lib:paths.bzl", "paths")
+
 def _build_static_transition_impl(_settings, _attr):
     """
     Transition that enables static build of Go and C binaries.
@@ -16,6 +18,41 @@
     ],
 )
 
+def _forward_impl(ctx):
+    # We can't pass DefaultInfo through as-is, since Bazel forbids executable
+    # if it's a file declared in a different target. To emulate that, symlink
+    # to the original executable, if there is one.
+    default_info = ctx.attr.dep[DefaultInfo]
+    new_executable = None
+    original_executable = default_info.files_to_run.executable
+    runfiles = default_info.default_runfiles
+    if original_executable:
+        # In order for the symlink to have the same basename as the original
+        # executable (important in the case of proto plugins), put it in a
+        # subdirectory named after the label to prevent collisions.
+        new_executable = ctx.actions.declare_file(paths.join(ctx.label.name, original_executable.basename))
+        ctx.actions.symlink(
+            output = new_executable,
+            target_file = original_executable,
+            is_executable = True,
+        )
+        runfiles = runfiles.merge(ctx.runfiles([new_executable]))
+
+    return [DefaultInfo(
+        files = default_info.files,
+        runfiles = runfiles,
+        executable = new_executable,
+    )]
+
+build_static_target = rule(
+    cfg = build_static_transition,
+    implementation = _forward_impl,
+    attrs = {
+        "dep": attr.label(mandatory = True),
+    },
+    doc = """Applies build_static_transition to a target.""",
+)
+
 _new_settings = {
     # This list should be expanded with any configuration options that end
     # up reaching this rule with different values across different build