diff --git a/.gitattributes b/.gitattributes index da576cd8d..00fb8f0c9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -41,3 +41,6 @@ pnpm-lock.yaml linguist-generated=true # The root Cargo lock is selected dependency topology and must stay visible. rust/Cargo.lock -linguist-generated + +# Central Reindeer output is deterministic dependency topology. +rust/third-party/BUCK linguist-generated=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0c8a539..9057444c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,28 @@ All notable changes to this project will be documented in this file. - Fix lazy Buck stage-0 recovery to snapshot only its fingerprinted source inputs, keep unrelated Cargo product manifests out of tool derivations, and retain the observability gate when shell-entry setup is disabled. +- **Buck2 megarepo product**: add Python-free, separately cacheable `mr`, + project-typecheck, and quality targets whose runtime and project closures + compose one package/tsconfig Genie registry. The exact product is checked by + the Nix runtime boundary; admission retains asserted invalidation and hostile + seam controls, while the benchmark explicitly reports the still-coarse + package-level production source boundary instead of claiming import-level + cache granularity. + - Harden Buck foundation review contracts by recording explicit revision and execution-platform receipt identity, redacting password aliases, validating schema-v3 provenance, preserving mutation-free observability checks, narrowing generated-file markings, and leasing in-flight publications against future collection. - Preserve pre-identity Buck receipt and dry-run compatibility while hardening dynamic ELF metadata boundaries, inspector failures, and artifact-seam mutation proofs. - Parse dynamic ELF dependency delimiters and version-need sections structurally, including non-numeric symbol versions without admitting local definition noise. - Preserve fixed-marker PT_INTERP paths and complete whitespace-bearing version-need names when inspecting dynamic ELF artifacts. - Bind Buck comparison receipts to the same repository revision and execution platform, preserve delimiter-like ELF version names, and keep the Rust toolchain flake call aligned with its minimal config API. +- **Native otel-scrape product**: generate a fine-grained Buck Rust graph from + the root Cargo/Reindeer resolution domain, compile a configured static-musl + library, binary, and unit harness without Cargo actions, and package an exact + `buck-build-product/v1` archive admitted by Nix's static-ELF inspector. Keep + the required self-derived import smoke test distinct from real admission, + which now requires an externally supplied descriptor digest with no fallback + and retains a literal Nix-side platform expectation. + - **Buck2/devenv fast path**: make shell activation independent of Buck and repository setup, expose the pinned Buck client through a source-mode local launcher, lazily resolve stage-0 tools only for consuming tasks, and classify @@ -35,7 +51,7 @@ All notable changes to this project will be documented in this file. descriptor digest for the shared Buck-to-Nix product envelope. Runtime is a required tagged union, invocation evidence is excluded from semantic product identity, and the importer now requires an independently supplied descriptor - digest and rejects every runtime until its real inspector exists. This removes + digest and rejects every runtime without an admitted inspector. This removes the synthetic shell import as evidence of an admitted portable product; the input-plan fixture is now labeled `buck2-package-evidence` rather than masquerading as a build product. Descriptor paths reject CR/LF bytes, fixed @@ -86,6 +102,15 @@ All notable changes to this project will be documented in this file. ### Fixed +- **Buck2 Rust toolchain identity**: bind every consumed compiler, linker, + binutils, documentation, lint, Python, and helper-PATH input into the single + Nix-authored identity, reconstruct the complete material independently in + Buck, and fail closed when a configured tool such as the archiver is omitted. + Project a separate minimal Rust compile/product identity so changes to + clippy, rustdoc, Python, or unused binutils do not invalidate compilation or + packaging. Bind that identity at Prelude's conventional compiler `RunInfo`, + so the real OTEL compile path verifies it before invoking `rustc`. + - **Buck2 pnpm prototype scope**: retain the exact lock-derived contextual dependency plan for `tui-core` while keeping it explicitly non-admitted. The prototype does not fetch, unpack, normalize, or materialize package archives. diff --git a/buck2/rust/BUCK b/buck2/rust/BUCK index 525435608..bea09b526 100644 --- a/buck2/rust/BUCK +++ b/buck2/rust/BUCK @@ -1,18 +1,39 @@ -load(":local_store.bzl", "rust_local_store_toolchain", "rust_static_binary") +load(":local_store.bzl", "rust_local_store_toolchain", "rust_static_binary", "rust_toolchain_config_integrity") # Nix owns these values. The invoking Nix/devenv launcher supplies exact store # paths with --config; they are command-line inputs to the local-only action. rust_local_store_toolchain( name = "x86_64_linux_musl_toolchain", + ar = read_config("rust_toolchain", "ar", ""), + cc = read_config("rust_toolchain", "cc", ""), + clippy_driver = read_config("rust_toolchain", "clippy_driver", ""), contract = read_config("rust_toolchain", "contract", ""), + cxx = read_config("rust_toolchain", "cxx", ""), + dwp = read_config("rust_toolchain", "dwp", ""), execution_platform = read_config("rust_toolchain", "execution_platform", ""), identity_verifier = read_config("rust_toolchain", "identity_verifier", ""), linker = read_config("rust_toolchain", "linker", ""), + nm = read_config("rust_toolchain", "nm", ""), + objcopy = read_config("rust_toolchain", "objcopy", ""), + objdump = read_config("rust_toolchain", "objdump", ""), + python = read_config("rust_toolchain", "python", ""), + ranlib = read_config("rust_toolchain", "ranlib", ""), rustc = read_config("rust_toolchain", "rustc", ""), + rustdoc = read_config("rust_toolchain", "rustdoc", ""), + strip = read_config("rust_toolchain", "strip", ""), target_platform = read_config("rust_toolchain", "target_platform", ""), target_triple = read_config("rust_toolchain", "target_triple", ""), - toolchain_identity_material = read_config("rust_toolchain", "toolchain_identity_material", ""), - toolchain_identity = read_config("rust_toolchain", "toolchain_identity", ""), + tool_path = read_config("rust_toolchain", "tool_path", ""), + config_integrity_material = read_config("rust_toolchain", "config_integrity_material", ""), + config_integrity_identity = read_config("rust_toolchain", "config_integrity_identity", ""), + compile_identity_material = read_config("rust_toolchain", "compile_identity_material", ""), + compile_identity = read_config("rust_toolchain", "compile_identity", ""), +) + +rust_toolchain_config_integrity( + name = "x86_64_linux_musl_config_integrity", + toolchain = ":x86_64_linux_musl_toolchain", + visibility = ["PUBLIC"], ) rust_static_binary( diff --git a/buck2/rust/local_store.bzl b/buck2/rust/local_store.bzl index 211592225..999d43ca8 100644 --- a/buck2/rust/local_store.bzl +++ b/buck2/rust/local_store.bzl @@ -1,15 +1,30 @@ """Exact Nix-store Rust tools for local-only target probes.""" RustLocalStoreToolchainInfo = provider(fields = [ + "ar", + "cc", + "clippy_driver", "contract", + "cxx", + "dwp", "execution_platform", "identity_verifier", "linker", + "nm", + "objcopy", + "objdump", + "python", + "ranlib", "rustc", + "rustdoc", + "strip", "target_platform", "target_triple", - "toolchain_identity", - "toolchain_identity_material", + "tool_path", + "compile_identity", + "compile_identity_material", + "config_integrity_identity", + "config_integrity_material", ]) _CONTRACT = "effect-utils/rust-local-store-toolchain/v1" @@ -21,28 +36,81 @@ def _require_nix_store_executable(value, name): if not value.startswith("/nix/store/") or "/bin/" not in value: fail("{} must be an absolute Nix store executable".format(name)) -def _require_toolchain_identity(value): +def _require_identity(value, name): if len(value) != 71 or not value.startswith("sha256:"): - fail("toolchain_identity must be a Nix-authored sha256 identity") + fail("{} must be a Nix-authored sha256 identity".format(name)) -def _identity_material(ctx): +def _require_nix_tool_path(value): + if not value: + fail("tool_path must be a non-empty list of immutable Nix store paths") + for path in value.split(":"): + if not path.startswith("/nix/store/") or not path.endswith("/bin"): + fail("tool_path entry must be an immutable Nix store bin directory: {}".format(path)) + +def _config_integrity_material(ctx): return ";".join([ + "ar=" + ctx.attrs.ar, + "cc=" + ctx.attrs.cc, + "clippy_driver=" + ctx.attrs.clippy_driver, "contract=" + ctx.attrs.contract, + "cxx=" + ctx.attrs.cxx, + "dwp=" + ctx.attrs.dwp, "execution_platform=" + ctx.attrs.execution_platform, "identity_verifier=" + ctx.attrs.identity_verifier, "linker=" + ctx.attrs.linker, + "nm=" + ctx.attrs.nm, + "objcopy=" + ctx.attrs.objcopy, + "objdump=" + ctx.attrs.objdump, + "python=" + ctx.attrs.python, + "ranlib=" + ctx.attrs.ranlib, "rustc=" + ctx.attrs.rustc, + "rustdoc=" + ctx.attrs.rustdoc, + "strip=" + ctx.attrs.strip, "target_platform=" + ctx.attrs.target_platform, "target_triple=" + ctx.attrs.target_triple, + "tool_path=" + ctx.attrs.tool_path, + ]) + +def _compile_identity_material(ctx): + return ";".join([ + "ar=" + ctx.attrs.ar, + "cc=" + ctx.attrs.cc, + "contract=" + ctx.attrs.contract, + "cxx=" + ctx.attrs.cxx, + "execution_platform=" + ctx.attrs.execution_platform, + "linker=" + ctx.attrs.linker, + "rustc=" + ctx.attrs.rustc, + "target_platform=" + ctx.attrs.target_platform, + "target_triple=" + ctx.attrs.target_triple, + "tool_path=" + ctx.attrs.tool_path, ]) def _rust_local_store_toolchain_impl(ctx): - _require_nix_store_executable(ctx.attrs.rustc, "rustc") - _require_nix_store_executable(ctx.attrs.linker, "linker") - _require_nix_store_executable(ctx.attrs.identity_verifier, "identity_verifier") - _require_toolchain_identity(ctx.attrs.toolchain_identity) - if ctx.attrs.toolchain_identity_material != _identity_material(ctx): - fail("Rust toolchain identity material does not match the configured fields") + for name, executable in [ + ("ar", ctx.attrs.ar), + ("cc", ctx.attrs.cc), + ("clippy_driver", ctx.attrs.clippy_driver), + ("cxx", ctx.attrs.cxx), + ("dwp", ctx.attrs.dwp), + ("identity_verifier", ctx.attrs.identity_verifier), + ("linker", ctx.attrs.linker), + ("nm", ctx.attrs.nm), + ("objcopy", ctx.attrs.objcopy), + ("objdump", ctx.attrs.objdump), + ("python", ctx.attrs.python), + ("ranlib", ctx.attrs.ranlib), + ("rustc", ctx.attrs.rustc), + ("rustdoc", ctx.attrs.rustdoc), + ("strip", ctx.attrs.strip), + ]: + _require_nix_store_executable(executable, name) + _require_nix_tool_path(ctx.attrs.tool_path) + _require_identity(ctx.attrs.config_integrity_identity, "config_integrity_identity") + _require_identity(ctx.attrs.compile_identity, "compile_identity") + if ctx.attrs.config_integrity_material != _config_integrity_material(ctx): + fail("Rust config-integrity material does not match the configured fields") + if ctx.attrs.compile_identity_material != _compile_identity_material(ctx): + fail("Rust compile-identity material does not match the configured fields") if ctx.attrs.contract != _CONTRACT: fail("unsupported Rust toolchain contract: {}".format(ctx.attrs.contract)) if ctx.attrs.execution_platform != _EXECUTION_PLATFORM: @@ -54,30 +122,85 @@ def _rust_local_store_toolchain_impl(ctx): return [ DefaultInfo(), RustLocalStoreToolchainInfo( + ar = ctx.attrs.ar, + cc = ctx.attrs.cc, + clippy_driver = ctx.attrs.clippy_driver, contract = ctx.attrs.contract, + cxx = ctx.attrs.cxx, + dwp = ctx.attrs.dwp, execution_platform = ctx.attrs.execution_platform, identity_verifier = ctx.attrs.identity_verifier, linker = ctx.attrs.linker, + nm = ctx.attrs.nm, + objcopy = ctx.attrs.objcopy, + objdump = ctx.attrs.objdump, + python = ctx.attrs.python, + ranlib = ctx.attrs.ranlib, rustc = ctx.attrs.rustc, + rustdoc = ctx.attrs.rustdoc, + strip = ctx.attrs.strip, target_platform = ctx.attrs.target_platform, target_triple = ctx.attrs.target_triple, - toolchain_identity = ctx.attrs.toolchain_identity, - toolchain_identity_material = ctx.attrs.toolchain_identity_material, + tool_path = ctx.attrs.tool_path, + compile_identity = ctx.attrs.compile_identity, + compile_identity_material = ctx.attrs.compile_identity_material, + config_integrity_identity = ctx.attrs.config_integrity_identity, + config_integrity_material = ctx.attrs.config_integrity_material, ), ] rust_local_store_toolchain = rule( impl = _rust_local_store_toolchain_impl, attrs = { + "ar": attrs.string(), + "cc": attrs.string(), + "clippy_driver": attrs.string(), "contract": attrs.string(), + "cxx": attrs.string(), + "dwp": attrs.string(), "execution_platform": attrs.string(), "identity_verifier": attrs.string(), "linker": attrs.string(), + "nm": attrs.string(), + "objcopy": attrs.string(), + "objdump": attrs.string(), + "python": attrs.string(), + "ranlib": attrs.string(), "rustc": attrs.string(), + "rustdoc": attrs.string(), + "strip": attrs.string(), "target_platform": attrs.string(), "target_triple": attrs.string(), - "toolchain_identity": attrs.string(), - "toolchain_identity_material": attrs.string(), + "tool_path": attrs.string(), + "compile_identity": attrs.string(), + "compile_identity_material": attrs.string(), + "config_integrity_identity": attrs.string(), + "config_integrity_material": attrs.string(), + }, +) + +def _config_integrity_impl(ctx): + toolchain = ctx.attrs.toolchain[RustLocalStoreToolchainInfo] + out = ctx.actions.declare_output("config-integrity.txt") + ctx.actions.run( + [ + toolchain.identity_verifier, + toolchain.config_integrity_material, + toolchain.config_integrity_identity, + "--stamp", + out.as_output(), + ], + category = "rust_toolchain_config_integrity", + env = {"PATH": "/nonexistent"}, + identifier = toolchain.config_integrity_identity[7:19], + local_only = True, + ) + return [DefaultInfo(default_output = out)] + +rust_toolchain_config_integrity = rule( + impl = _config_integrity_impl, + attrs = { + "toolchain": attrs.exec_dep(providers = [RustLocalStoreToolchainInfo]), }, ) @@ -87,8 +210,8 @@ def _rust_static_binary_impl(ctx): ctx.actions.run( [ toolchain.identity_verifier, - toolchain.toolchain_identity_material, - toolchain.toolchain_identity, + toolchain.compile_identity_material, + toolchain.compile_identity, toolchain.rustc, ctx.attrs.src, "--crate-name", @@ -109,7 +232,7 @@ def _rust_static_binary_impl(ctx): ], category = "rust_compile", env = {"PATH": "/nonexistent"}, - identifier = "{}-{}".format(toolchain.target_triple, toolchain.toolchain_identity[7:19]), + identifier = "{}-{}".format(toolchain.target_triple, toolchain.compile_identity[7:19]), local_only = True, ) return [DefaultInfo(default_output = out), RunInfo(args = cmd_args(out))] diff --git a/buck2/rust_product.bzl b/buck2/rust_product.bzl new file mode 100644 index 000000000..eca7b71f3 --- /dev/null +++ b/buck2/rust_product.bzl @@ -0,0 +1,55 @@ +"""Exact Buck build-product packaging for one Nix-authored static Rust lane.""" + +BuildProductInfo = provider(fields = ["archive", "descriptor"]) + +def _single_output(dep): + outputs = dep[DefaultInfo].default_outputs + if len(outputs) != 1: + fail("rust_build_product requires exactly one binary output") + return outputs[0] + +def _impl(ctx): + identity = ctx.attrs.compile_identity + if len(identity) != 71 or not identity.startswith("sha256:"): + fail("compile_identity must be a Nix-authored sha256 identity") + archive = ctx.actions.declare_output("artifact.tar") + descriptor = ctx.actions.declare_output("descriptor.json") + ctx.actions.run( + [ + ctx.attrs._packager[RunInfo], + "product", + "--binary", _single_output(ctx.attrs.binary), + "--binary-name", ctx.attrs.binary_name, + "--target", str(ctx.label), + "--toolchain-identity", identity, + "--archive", archive.as_output(), + "--descriptor", descriptor.as_output(), + ], + category = "rust_build_product", + env = {"PATH": "/nonexistent"}, + identifier = ctx.attrs.binary_name, + local_only = True, + ) + return [ + DefaultInfo( + default_output = archive, + other_outputs = [descriptor], + sub_targets = { + "descriptor": [DefaultInfo(default_output = descriptor)], + }, + ), + BuildProductInfo(archive = archive, descriptor = descriptor), + ] + +rust_build_product = rule( + impl = _impl, + attrs = { + "binary": attrs.dep(), + "binary_name": attrs.string(), + "compile_identity": attrs.string(), + "_packager": attrs.default_only(attrs.exec_dep( + default = "toolchains//:package_evidence_tool", + providers = [RunInfo], + )), + }, +) diff --git a/buck2/toolchains/conventional_probe.bzl b/buck2/toolchains/conventional_probe.bzl new file mode 100644 index 000000000..274eb9695 --- /dev/null +++ b/buck2/toolchains/conventional_probe.bzl @@ -0,0 +1,41 @@ +"""Execution proof for Prelude's conventional Rust and C++ toolchain providers.""" + +load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxToolchainInfo") +load("@prelude//rust:rust_toolchain.bzl", "RustToolchainInfo") + +def _impl(ctx): + identity = ctx.attrs.toolchain_identity + if len(identity) != 71 or not identity.startswith("sha256:"): + fail("toolchain_identity must be a Nix-authored sha256 identity") + rust = ctx.actions.declare_output("rustc.version") + cxx = ctx.actions.declare_output("cc.version") + ctx.actions.run( + [ctx.attrs._rust[RustToolchainInfo].compiler, "--version", "--verbose"], + category = "conventional_rust_toolchain_probe", + env = {"EFFECT_UTILS_BUCK2_TOOLCHAIN_IDENTITY": identity}, + local_only = True, + stdout = rust.as_output(), + ) + ctx.actions.run( + [ctx.attrs._cxx[CxxToolchainInfo].c_compiler_info.compiler, "--version"], + category = "conventional_cxx_toolchain_probe", + env = {"EFFECT_UTILS_BUCK2_TOOLCHAIN_IDENTITY": identity}, + local_only = True, + stdout = cxx.as_output(), + ) + return [DefaultInfo(default_outputs = [rust, cxx])] + +conventional_toolchain_probe = rule( + impl = _impl, + attrs = { + "toolchain_identity": attrs.string(), + "_rust": attrs.default_only(attrs.exec_dep( + default = "toolchains//:rust", + providers = [RustToolchainInfo], + )), + "_cxx": attrs.default_only(attrs.exec_dep( + default = "toolchains//:cxx", + providers = [CxxToolchainInfo], + )), + }, +) diff --git a/buck2/toolchains/nix_local.bzl b/buck2/toolchains/nix_local.bzl new file mode 100644 index 000000000..75f508ae7 --- /dev/null +++ b/buck2/toolchains/nix_local.bzl @@ -0,0 +1,262 @@ +"""Nix-authored, local-only Rust/C++ toolchain providers for Buck2. + +The configured values are immutable Nix store *roots*, not executable paths. +Keeping the roots explicit makes the action key include the complete toolchain +identity while preventing a mutable PATH lookup from changing the compiler. + +Raw host store paths are intentionally a local execution boundary. A future +remote-execution lane must replace these providers with portable artifacts and +an execution-platform constraint; a provider cannot itself force every Prelude +consumer action to be local-only. +""" + +load( + "@prelude//cxx:cxx_toolchain_types.bzl", + "BinaryUtilitiesInfo", + "CCompilerInfo", + "CxxCompilerInfo", + "CxxInternalTools", + "DepTrackingMode", + "LinkerInfo", + "LinkerType", + "PicBehavior", + "ShlibInterfacesMode", + "cxx_toolchain_infos", +) +load("@prelude//cxx:headers.bzl", "HeaderMode") +load("@prelude//linking:link_info.bzl", "LinkStyle") +load("@prelude//linking:lto.bzl", "LtoMode") +load("@prelude//rust:rust_toolchain.bzl", "PanicRuntime", "RustToolchainInfo") +load( + "@prelude//toolchains:python.bzl", + "system_python_bootstrap_toolchain", + "system_python_toolchain", +) + +def _configured_target_triple(): + value = read_root_config("rust_toolchain", "target_triple", "") + if value != "x86_64-unknown-linux-musl": + fail("Nix-local Rust/C++ toolchains admit only x86_64-unknown-linux-musl") + return value + +def _configured_exec(key): + value = read_root_config("rust_toolchain", key, "") + if not value.startswith("/nix/store/") or "/bin/" not in value: + fail("rust_toolchain.{} must be an immutable Nix store executable".format(key)) + return value + +def _require_identity(value, name): + if len(value) != 71 or not value.startswith("sha256:"): + fail("{} must be a Nix-authored sha256 identity".format(name)) + +def _compile_identity_material(ctx): + return ";".join([ + "ar=" + ctx.attrs.ar, + "cc=" + ctx.attrs.cc, + "contract=" + ctx.attrs.contract, + "cxx=" + ctx.attrs.cxx, + "execution_platform=" + ctx.attrs.execution_platform, + "linker=" + ctx.attrs.linker, + "rustc=" + ctx.attrs.rustc, + "target_platform=" + ctx.attrs.target_platform, + "target_triple=" + ctx.attrs.target_triple, + "tool_path=" + ctx.attrs.tool_path, + ]) + +def _nix_rust_toolchain_impl(ctx): + _require_identity(ctx.attrs.compile_identity, "compile_identity") + if ctx.attrs.compile_identity_material != _compile_identity_material(ctx): + fail("Rust compile-identity material does not match the conventional toolchain fields") + return [ + DefaultInfo(), + RustToolchainInfo( + compiler = RunInfo(args = [ + ctx.attrs.identity_verifier, + ctx.attrs.compile_identity_material, + ctx.attrs.compile_identity, + ctx.attrs.rustc, + ]), + rustdoc = RunInfo(args = [ctx.attrs.rustdoc]), + clippy_driver = RunInfo(args = [ctx.attrs.clippy_driver]), + default_edition = "2021", + panic_runtime = PanicRuntime("unwind"), + rustc_target_triple = ctx.attrs.target_triple, + # Cargo build scripts consult these when compiling native probes. + # The values are immutable executables, not PATH-relative names. + rustc_env = { + "AR": ctx.attrs.ar, + "CC": ctx.attrs.cc, + "CXX": ctx.attrs.cxx, + "LD": ctx.attrs.linker, + # Prelude emits small `/usr/bin/env bash` wrappers. Constrain + # their lookup and helper utilities to reviewed store roots. + "PATH": ctx.attrs.tool_path, + }, + ), + ] + +_nix_rust_toolchain = rule( + impl = _nix_rust_toolchain_impl, + attrs = { + "ar": attrs.string(), + "cc": attrs.string(), + "clippy_driver": attrs.string(), + "compile_identity": attrs.string(), + "compile_identity_material": attrs.string(), + "contract": attrs.string(), + "cxx": attrs.string(), + "execution_platform": attrs.string(), + "identity_verifier": attrs.string(), + "linker": attrs.string(), + "rustc": attrs.string(), + "rustdoc": attrs.string(), + "target_platform": attrs.string(), + "target_triple": attrs.string(), + "tool_path": attrs.string(), + }, + is_toolchain_rule = True, +) + +def _compiler_info(provider, compiler): + return provider( + compiler = RunInfo(args = [compiler]), + compiler_flags = [], + compiler_type = "gcc", + preprocessor_flags = [], + supports_content_based_paths = False, + ) + +def _nix_cxx_toolchain_impl(ctx): + c_compiler = _compiler_info(CCompilerInfo, ctx.attrs.cc) + cxx_compiler = _compiler_info(CxxCompilerInfo, ctx.attrs.cxx) + linker = LinkerInfo( + archiver = RunInfo(args = [ctx.attrs.ar]), + archiver_supports_argfiles = True, + archiver_type = "gnu", + archive_objects_locally = True, + binary_extension = "", + generate_linker_maps = False, + link_binaries_locally = True, + link_libraries_locally = True, + link_style = LinkStyle("static"), + linker = RunInfo(args = [ctx.attrs.linker]), + linker_flags = [], + lto_mode = LtoMode("none"), + object_file_extension = "o", + shlib_interfaces = ShlibInterfacesMode("disabled"), + shared_dep_runtime_ld_flags = [], + shared_library_name_default_prefix = "lib", + shared_library_name_format = "{}.so", + shared_library_versioned_name_format = "{}.so.{}", + static_dep_runtime_ld_flags = [], + static_library_extension = "a", + static_pic_dep_runtime_ld_flags = [], + type = LinkerType("gnu"), + use_archiver_flags = True, + ) + binary_utilities = BinaryUtilitiesInfo( + dwp = RunInfo(args = [ctx.attrs.dwp]), + nm = RunInfo(args = [ctx.attrs.nm]), + objcopy = RunInfo(args = [ctx.attrs.objcopy]), + objdump = RunInfo(args = [ctx.attrs.objdump]), + ranlib = RunInfo(args = [ctx.attrs.ranlib]), + strip = RunInfo(args = [ctx.attrs.strip]), + ) + return [DefaultInfo()] + cxx_toolchain_infos( + platform_name = ctx.attrs.platform_name, + c_compiler_info = c_compiler, + cxx_compiler_info = cxx_compiler, + linker_info = linker, + binary_utilities_info = binary_utilities, + header_mode = HeaderMode("symlink_tree_only"), + internal_tools = ctx.attrs.internal_tools[CxxInternalTools], + cpp_dep_tracking_mode = DepTrackingMode("makefile"), + pic_behavior = PicBehavior("supported"), + use_dep_files = True, + ) + +_nix_cxx_toolchain = rule( + impl = _nix_cxx_toolchain_impl, + attrs = { + "ar": attrs.string(), + "cc": attrs.string(), + "cxx": attrs.string(), + "dwp": attrs.string(), + "internal_tools": attrs.default_only(attrs.exec_dep( + default = "prelude//cxx/tools:internal_tools", + providers = [CxxInternalTools], + )), + "linker": attrs.string(), + "nm": attrs.string(), + "objcopy": attrs.string(), + "objdump": attrs.string(), + "platform_name": attrs.string(), + "ranlib": attrs.string(), + "strip": attrs.string(), + }, + is_toolchain_rule = True, +) + +def nix_local_rust_cxx_python_toolchains(): + # The shared toolchains package also owns language-neutral stage-0 tools. + # Only Rust product invocations supply this separately rooted config. + if not read_root_config("rust_toolchain", "rustc", ""): + return + + rustc = _configured_exec("rustc") + rustdoc = _configured_exec("rustdoc") + cc = _configured_exec("cc") + cxx = _configured_exec("cxx") + linker = _configured_exec("linker") + ar = _configured_exec("ar") + python = _configured_exec("python") + + # Prelude's Python helpers are part of the build graph. Pin both the normal + # and bootstrap providers to the same immutable Nix interpreter instead of + # downloading and extracting a second CPython distribution at action time. + system_python_toolchain( + name = "python", + interpreter = python, + visibility = ["PUBLIC"], + ) + system_python_bootstrap_toolchain( + name = "python_bootstrap", + interpreter = python, + visibility = ["PUBLIC"], + ) + + _nix_cxx_toolchain( + name = "cxx", + ar = ar, + cc = cc, + cxx = cxx, + dwp = _configured_exec("dwp"), + linker = linker, + nm = _configured_exec("nm"), + objcopy = _configured_exec("objcopy"), + objdump = _configured_exec("objdump"), + platform_name = _configured_target_triple(), + ranlib = _configured_exec("ranlib"), + strip = _configured_exec("strip"), + visibility = ["PUBLIC"], + ) + + _nix_rust_toolchain( + name = "rust", + ar = ar, + cc = cc, + clippy_driver = _configured_exec("clippy_driver"), + compile_identity = read_root_config("rust_toolchain", "compile_identity", ""), + compile_identity_material = read_root_config("rust_toolchain", "compile_identity_material", ""), + contract = read_root_config("rust_toolchain", "contract", ""), + cxx = cxx, + execution_platform = read_root_config("rust_toolchain", "execution_platform", ""), + identity_verifier = _configured_exec("identity_verifier"), + linker = linker, + rustc = rustc, + rustdoc = rustdoc, + target_platform = read_root_config("rust_toolchain", "target_platform", ""), + target_triple = _configured_target_triple(), + tool_path = read_root_config("rust_toolchain", "tool_path", ""), + visibility = ["PUBLIC"], + ) diff --git a/buck2/typescript.bzl b/buck2/typescript.bzl new file mode 100644 index 000000000..505c687bc --- /dev/null +++ b/buck2/typescript.bzl @@ -0,0 +1,84 @@ +"""Python-free TypeScript product rules with explicit source and tool edges.""" + +def _configured_path(section, key): + value = read_root_config(section, key, "") + parts = value.split("/") + if (not value.startswith("/nix/store/") or "\n" in value or "\r" in value or len(parts) < 4 or parts[0] != "" or parts[1] != "nix" or parts[2] != "store" or any([part == "" or part == "." or part == ".." for part in parts[3:]])): + fail("{}.{} must be an immutable absolute /nix/store path".format(section, key)) + return value + +def _local_nix_platform(): + host = host_info() + architecture = "x86_64" if host.arch.is_x86_64 else "aarch64" if host.arch.is_aarch64 else fail("unsupported host architecture") + operating_system = "linux" if host.os.is_linux else "darwin" if host.os.is_macos else fail("unsupported host operating system") + return architecture + "-" + operating_system + +def _add_sources(args, package_path, sources, workspace_sources, workspace_source_prefixes): + for source in sources: + args.add("--source-label", package_path + "/" + source.short_path, "--source", source) + for dep in workspace_sources: + label = str(dep.label.raw_target()) + if label.startswith("root//"): + label = label.removeprefix("root") + if label not in workspace_source_prefixes: + fail("workspace source dependency has no staging prefix: {}".format(label)) + outputs = dep[DefaultInfo].default_outputs + if len(outputs) == 0: + fail("workspace source dependency must expose at least one artifact: {}".format(label)) + for output in outputs: + args.add("--source-label", workspace_source_prefixes[label] + "/" + output.short_path, "--source", output) + +def _check_impl(ctx): + local_platform = _local_nix_platform() + if ctx.attrs.platform != local_platform: + fail("typescript_project_check platform mismatch: target requires {}, local-only execution host is {}".format(ctx.attrs.platform, local_platform)) + output = ctx.actions.declare_output("typecheck.json") + args = cmd_args([ctx.attrs._tool[RunInfo], "check", "--tsgo", ctx.attrs._tsgo, "--dependency-root", ctx.attrs._dependency_root, "--tsconfig", ctx.attrs.tsconfig, "--output", output.as_output()]) + for native in ctx.attrs._native_packages: + args.add("--native-package", native) + _add_sources(args, ctx.attrs.package_path, ctx.attrs.srcs, ctx.attrs.workspace_sources, ctx.attrs.workspace_source_prefixes) + ctx.actions.run(args, env = {"PATH": "/nonexistent"}, category = "typescript_project_check", identifier = ctx.attrs.name, local_only = True) + return [DefaultInfo(default_output = output)] + +_typescript_project_check = rule( + impl = _check_impl, + attrs = { + "package_path": attrs.string(), "platform": attrs.string(), "srcs": attrs.list(attrs.source()), "tsconfig": attrs.string(), + "workspace_sources": attrs.list(attrs.dep()), "workspace_source_prefixes": attrs.dict(attrs.string(), attrs.string()), + "_tsgo": attrs.default_only(attrs.string(default = _configured_path("buck2_nix", "tsgo"))), + "_dependency_root": attrs.default_only(attrs.string(default = _configured_path("buck2_nix", "megarepo_deps"))), + "_native_packages": attrs.default_only(attrs.list(attrs.string(), default = ["@opentui/core-linux-x64=" + _configured_path("buck2_nix", "opentui_glibc"), "@opentui/core-linux-x64-musl=" + _configured_path("buck2_nix", "opentui_musl") ])), + "_tool": attrs.default_only(attrs.exec_dep(default = "toolchains//:typescript_product_tool", providers = [RunInfo])), + }, +) + +def _cli_impl(ctx): + local_platform = _local_nix_platform() + if ctx.attrs.platform != local_platform: + fail("typescript_cli platform mismatch: target requires {}, local-only execution host is {}".format(ctx.attrs.platform, local_platform)) + binary = ctx.actions.declare_output(ctx.attrs.binary_name) + archive = ctx.actions.declare_output("artifact.tar") + descriptor = ctx.actions.declare_output("descriptor.json") + args = cmd_args([ctx.attrs._tool[RunInfo], "bundle", "--bun", ctx.attrs._bun, "--patchelf", ctx.attrs._patchelf, "--dependency-root", ctx.attrs._dependency_root, "--entry", ctx.attrs.entry, "--binary-name", ctx.attrs.binary_name, "--output", binary.as_output(), "--archive", archive.as_output(), "--descriptor", descriptor.as_output(), "--target", str(ctx.label.raw_target()), "--platform", ctx.attrs.platform]) + for native in ctx.attrs._native_packages: + args.add("--native-package", native) + _add_sources(args, ctx.attrs.package_path, ctx.attrs.srcs, ctx.attrs.workspace_sources, ctx.attrs.workspace_source_prefixes) + ctx.actions.run(args, env = {"PATH": "/nonexistent"}, category = "typescript_cli_compile", identifier = ctx.attrs.binary_name, local_only = True) + return [DefaultInfo(default_output = archive, other_outputs = [binary, descriptor], sub_targets = {"artifact": [DefaultInfo(default_output = archive)], "binary": [DefaultInfo(default_output = binary)], "descriptor": [DefaultInfo(default_output = descriptor)]}), RunInfo(args = cmd_args(binary))] + +_typescript_cli = rule( + impl = _cli_impl, + attrs = { + "entry": attrs.string(), "package_path": attrs.string(), "binary_name": attrs.string(), "platform": attrs.string(), "srcs": attrs.list(attrs.source()), + "workspace_sources": attrs.list(attrs.dep()), "workspace_source_prefixes": attrs.dict(attrs.string(), attrs.string()), + "_bun": attrs.default_only(attrs.string(default = _configured_path("buck2_nix", "bun"))), "_patchelf": attrs.default_only(attrs.string(default = _configured_path("buck2_nix", "patchelf"))), "_dependency_root": attrs.default_only(attrs.string(default = _configured_path("buck2_nix", "megarepo_deps"))), + "_native_packages": attrs.default_only(attrs.list(attrs.string(), default = ["@opentui/core-linux-x64=" + _configured_path("buck2_nix", "opentui_glibc"), "@opentui/core-linux-x64-musl=" + _configured_path("buck2_nix", "opentui_musl") ])), + "_tool": attrs.default_only(attrs.exec_dep(default = "toolchains//:typescript_product_tool", providers = [RunInfo])), + }, +) + +def typescript_project_check(name, package_path, platform, tsconfig, srcs, workspace_sources, workspace_source_prefixes): + _typescript_project_check(name = name, package_path = package_path, platform = platform, tsconfig = tsconfig, srcs = srcs, workspace_sources = workspace_sources, workspace_source_prefixes = workspace_source_prefixes) + +def typescript_cli(name, package_path, entry, binary_name, platform, srcs, workspace_sources, workspace_source_prefixes): + _typescript_cli(name = name, package_path = package_path, entry = entry, binary_name = binary_name, platform = platform, srcs = srcs, workspace_sources = workspace_sources, workspace_source_prefixes = workspace_source_prefixes) diff --git a/context/buck2/02-execution-platforms/requirements.md b/context/buck2/02-execution-platforms/requirements.md index c114cae9b..f95a3ce6a 100644 --- a/context/buck2/02-execution-platforms/requirements.md +++ b/context/buck2/02-execution-platforms/requirements.md @@ -91,6 +91,16 @@ protocol, entrypoint, platform, and runtime behavior are unchanged. The exact artifact, not merely a package name, version string, store prefix, or ambient executable path, MUST participate in the consuming action key. +For an aggregate compiler provider, the identity material MUST enumerate every +configured executable and search path that any exposed language, linker, +archiver, binary-utility, documentation, lint, build-script, or action-helper +surface consumes. Omitting one field MUST fail closed rather than preserve the +aggregate identity. +That complete configuration-integrity identity MUST NOT be used as a universal +action or product identity. Each action class and product descriptor MUST bind +only the tools and semantic claims it consumes, so changing an unrelated lint, +documentation, Python, or binary-utility tool does not invalidate compilation +or packaging. ### BUCK.PLAT-R007: per-platform stage 0 diff --git a/context/buck2/02-execution-platforms/spec.md b/context/buck2/02-execution-platforms/spec.md index 87d042b1c..1cce20127 100644 --- a/context/buck2/02-execution-platforms/spec.md +++ b/context/buck2/02-execution-platforms/spec.md @@ -238,6 +238,32 @@ ExecutionToolInfo Compiler toolchains may aggregate several tools when the compiler contract requires them to change together. Leaf helpers remain separate exec deps. +The local-store Rust aggregate reconstructs a complete ordered integrity +material string independently on each side of the boundary. It includes `rustc`, +`rustdoc`, `clippy-driver`, linker, C and C++ compilers, archiver, every exposed +binutils executable, Python, and the complete helper `PATH`, in addition to the +contract and target/execution-platform claims. Nix hashes that material; Buck +requires every path to be an immutable store executable (or, for `PATH`, an +ordered colon-separated set of store `bin` directories), reconstructs the same +bytes from individual configured fields, and rejects any omission or mismatch +before creating the provider. This integrity root detects mixed configuration; +it is not threaded through every action. + +The initial Rust compile identity is a separate projection containing only +`rustc`, linker, C compiler, C++ compiler, archiver, helper `PATH`, contract, +target triple, and target/execution-platform claims. Prelude exposes those +values to compilation and build-script-capable Rust actions. The OTEL compile +actions and build-product descriptor use this projection. `rustdoc`, +`clippy-driver`, Python, `dwp`, `nm`, `objcopy`, `objdump`, `ranlib`, and `strip` +remain covered by configuration integrity but do not invalidate compile or +package outputs until an action explicitly consumes them. + +Prelude's conventional Rust provider independently reconstructs this same +projection from its individual configured attributes. Its compiler `RunInfo` +invokes the immutable identity verifier with the material and digest before +`rustc`, making the check part of every real conventional compile action. The +OTEL product's false-identity control therefore traverses the production +library/binary/package graph rather than relying on the separate static probe. Packaging-only, test-only, and lint-only providers are attached only to their respective actions. diff --git a/context/buck2/03-target-execution/01-typescript/2026-08-13-megarepo-product-prototype.md b/context/buck2/03-target-execution/01-typescript/2026-08-13-megarepo-product-prototype.md new file mode 100644 index 000000000..ae3ec4a7c --- /dev/null +++ b/context/buck2/03-target-execution/01-typescript/2026-08-13-megarepo-product-prototype.md @@ -0,0 +1,48 @@ +# Megarepo Product Prototype Evidence + +Date: 2026-08-13 + +Target: `//packages/@overeng/megarepo:mr` + +## Verified + +- The repository-owned action helper is Rust; the product path adds no Python + executable or Python source edge. +- Generated role closures recursively compose runtime workspace dependencies + from the package Genie SSOT and project references from the tsconfig Genie + SSOT. The same tsconfig facets derive every project file set, including + `tui-react` tests and examples. One shared workspace registry pairs both + facets, so package names are not maintained in independent generators; + unknown first-party edges fail generation. No generator reads ambient + `node_modules` or hashes whole lockfiles. +- Workspace filegroups are expanded to individual source artifacts with stable + staging prefixes. The `mr` product has no edge to the typecheck marker; + `mr_quality` is the explicit aggregate that joins both sibling targets. +- Git revision, commit timestamp, dirty state, invocation ID, and action + evidence do not enter the executable bytes or semantic descriptor. +- `buck2-typescript-product` unit tests, Cargo check, and Clippy with warnings + denied passed; the generated-file check reported 103 of 103 files current. + +## No Verdict + +- The host had approximately 41 GB free, below the 200 GB heavy-build policy + floor, so no new Nix realization, full Buck product build, runtime smoke, + invalidation run, or benchmark was admitted. +- Buck target analysis and dependency queries passed after starting the pinned + Watchman. They prove `mr_quality` joins `mr`, `typecheck`, and the recursive + project closure. The E2E task builds that aggregate and includes an actual + included-test-file type-error RED/GREEN control before import, then asserts + independent platform, payload-digest, and observed-runtime RED seams. The + full product action and these executable controls were not executed. +- The benchmark distinguishes two formerly conflated boundaries. A + role-excluded test mutation must execute zero product actions. A dedicated + production-declared but entrypoint-unreachable source mutation must execute + at least one action, explicitly exposing the current package-level closure as + coarse. Relevant entrypoint-reachable mutations must also execute at least + one action; warm and mtime-only observations must execute zero. No benchmark + was admitted on this host, and the package-level production boundary remains + unadmitted rather than being mislabeled dependency-closure granularity. +- The emitted strict `buck-build-product/v1` descriptor has an implemented Nix + import path. Its `elf-dynamic/v1` runtime inspector validates loader, + dependency, symbol-version, runpath, and store-reference facts against the + descriptor. Execution of that path remains no-verdict on this host. diff --git a/context/buck2/03-target-execution/01-typescript/requirements.md b/context/buck2/03-target-execution/01-typescript/requirements.md index eccb4993c..c134b4bdd 100644 --- a/context/buck2/03-target-execution/01-typescript/requirements.md +++ b/context/buck2/03-target-execution/01-typescript/requirements.md @@ -38,8 +38,9 @@ validation, tests, and standalone executable production. workspace-package edges that can affect a result must be declared inputs. Refines: BUCK.EXEC-R03, BUCK.EXEC-R04. - **BUCK.EXEC.TS-R03 Entry and output identity:** An executable target must name - one declared entrypoint, output name, build identity input, runtime ABI, and - target platform. + one declared entrypoint, output name, release-version input, runtime ABI, and + target platform. Invocation evidence such as Git revision, timestamp, or dirty + state must not enter product bytes or semantic descriptor identity. Refines: BUCK.EXEC-R02, BUCK.EXEC-R17. ### Must isolate dependency and tool execution @@ -83,3 +84,7 @@ validation, tests, and standalone executable production. verified Buck artifact and does not rebuild the TypeScript sources independently. Refines: BUCK.EXEC-R17. +- **BUCK.EXEC.TS-R12 Role closure projection:** Runtime and quality source + closures must derive from the package and tsconfig authoring SSOT. Whole + repository or lockfile digests must not stand in for the selected task closure. + Refines: BUCK.EXEC-R03, BUCK.EXEC-R04. diff --git a/context/buck2/03-target-execution/01-typescript/spec.md b/context/buck2/03-target-execution/01-typescript/spec.md index fc84a0c0a..c8cec413b 100644 --- a/context/buck2/03-target-execution/01-typescript/spec.md +++ b/context/buck2/03-target-execution/01-typescript/spec.md @@ -4,7 +4,7 @@ This document specifies TypeScript target execution. It refines the shared [target execution spec](../spec.md) and satisfies [requirements.md](./requirements.md). -Status: **Draft** +Status: **Draft; mr product prototype is not admitted for Nix import** ## Scope @@ -59,7 +59,7 @@ interface TypeScriptExecutable extends TypeScriptOperation { readonly kind: 'executable' readonly entry: RepoRelativePath readonly outputName: string - readonly buildIdentity: BuildIdentityInput + readonly releaseVersion: ReleaseVersionInput readonly runtimeAbi: RuntimeAbi } ``` @@ -166,11 +166,35 @@ project-check marker --------------------> aggregate quality gate artifact packaging ``` -Compilation injects the shared build-identity contract at the executable leaf -and emits one raw executable provider. Normalization applies the configured +Compilation injects only an explicit release version at the executable leaf +and emits one raw executable provider. Git SHA, commit timestamp, dirty state, +invocation ID, and action evidence remain in the launcher receipt and never +affect product bytes or semantic descriptor identity. Normalization applies the configured runtime ABI without changing language semantics. Packaging emits the shared artifact provider and structured provenance. -The deployment consumer verifies and imports that artifact. It may add system +The current `//packages/@overeng/megarepo:mr` prototype emits the strict +`buck-build-product/v1` descriptor and is verified by the Nix importer's +`elf-dynamic/v1` runtime inspector. The deployment consumer verifies and +imports that artifact. It may add system wrappers or runtime dependencies, but it does not invoke the TypeScript compiler, runtime bundler, or package manager against repository sources. + +The generated role projections recursively compose runtime workspace +dependencies from `package.json.genie.ts` and project-check references from +`tsconfig.json.genie.ts`. Both facets share one fail-closed workspace registry, +while their edges remain role-specific. Tsconfig include and exclude facets +also derive each project file set, so tests, examples, stories, fixtures, and +every source admitted by the real tsconfig participate in checking; product +compilation excludes quality-only sources. The selected immutable Nix +dependency closure, Bun tool, and stage-0 Rust product tool remain separate +declared Buck inputs. The dependency closure is an explicitly unadmitted +granularity boundary. The current source projection is also package-level: an +entrypoint-unreachable file in a reachable package is still a declared product +input and therefore invalidates the product action. The asserted benchmark must +record that coarse boundary as a positive action count; it must separately +prove role-excluded test edits, warm no-ops, and mtime-only changes execute zero +actions, while entrypoint-reachable edits execute at least one. Neither the +package source closure nor the opaque external dependency closure is admitted +as fine-grained until a sound generated module/dependency projection replaces +the package-level input and its own negative controls pass. diff --git a/context/buck2/03-target-execution/02-rust/spec.md b/context/buck2/03-target-execution/02-rust/spec.md index 3f941cd01..18aa6f478 100644 --- a/context/buck2/03-target-execution/02-rust/spec.md +++ b/context/buck2/03-target-execution/02-rust/spec.md @@ -4,7 +4,10 @@ This document specifies Rust target execution. It refines the shared [target execution spec](../spec.md) and satisfies [requirements.md](./requirements.md). -Status: **Draft** +Status: **Draft**. `otel-scrape` now has generated first-party library, binary, +and unit-test targets on the configured `x86_64-linux-musl` lane. They consume +the central Reindeer projection from `rust/Cargo.toml` plus `rust/Cargo.lock`; +integration tests and other platforms remain unadmitted. ## Scope diff --git a/context/buck2/04-artifact-system-bridge/.experiments/2026-08-13-otel-independent-admission.md b/context/buck2/04-artifact-system-bridge/.experiments/2026-08-13-otel-independent-admission.md new file mode 100644 index 000000000..e5e8dee1c --- /dev/null +++ b/context/buck2/04-artifact-system-bridge/.experiments/2026-08-13-otel-independent-admission.md @@ -0,0 +1,29 @@ +# OTEL Independent Admission Authority + +## Status + +Structural proof complete on 2026-08-13. Product realization is **NO VERDICT** +because the host had less than 60 GB free and heavy work was not admitted. + +## Question + +Can the repository keep an executable Buck-to-Nix smoke gate without letting +the product-producing invocation authorize its own descriptor identity? + +## Result + +The shared runner has two explicit modes: + +| Mode | Descriptor expectation | Required CI | Authority | +| ------- | ------------------------------------------------------- | ----------- | --------------------- | +| `smoke` | Derived from the produced descriptor | Yes | Plumbing only | +| `admit` | `BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST` from the caller | No | Independent admission | + +Both modes keep `linux/x86_64/musl` as literal Nix policy. Both first substitute +a different, still schema-valid semantic recipe while retaining the original +expected digest and require a descriptor-identity rejection. The unchanged +descriptor must then import under the same pin. + +Focused evidence covered shell syntax, Nix parsing, task wiring, the absence of +an admission fallback, and the exact RED/GREEN data flow. It did not realize the +cross toolchain, Buck product, or Nix import. diff --git a/context/buck2/04-artifact-system-bridge/spec.md b/context/buck2/04-artifact-system-bridge/spec.md index fde4c6bd2..d0ac53631 100644 --- a/context/buck2/04-artifact-system-bridge/spec.md +++ b/context/buck2/04-artifact-system-bridge/spec.md @@ -6,10 +6,10 @@ the handoff into Nix-managed system generations. It builds on Status: **Draft**. The exact descriptor validator and canonical identity are implemented, and the generic archive/import seam plus OCI protocol have -prototype evidence. The importer admits the exact observation-only -`elf-dynamic/v1` runtime inspector on the supported Linux/glibc tuples and -rejects every other runtime. No TypeScript or Rust executable, publication -flow, or system generation is admitted through the bridge. +prototype evidence. The importer dispatches exact inspectors for dynamic +Linux/glibc ELF and static Linux/x86_64-musl ELF products after archive, digest, +size, platform, entrypoint, dependency, and store-reference checks. Other +runtimes, publication, and system generation remain unadmitted. ## Scope @@ -144,6 +144,18 @@ expected descriptor digest + provenance policy ``` +An admission invocation must receive `BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST` +from an authority outside the product-producing invocation. It has no +self-derived fallback. The expected platform remains the literal Nix policy +`linux/x86_64/musl`; it is never copied from the candidate descriptor. + +The required repository check is explicitly an import smoke test, not an +admission decision. It may derive the candidate descriptor digest to exercise +the Buck-output-to-Nix plumbing. Both workflows reuse the same runner and prove +the identity seam with a valid descriptor-substitution RED (modified semantic +provenance under the original expected digest) followed by a GREEN using that +same pin. Only the externally pinned workflow may claim admission authority. + Import is fail closed: 1. Verify and strictly decode the descriptor against the external expectation. diff --git a/devenv.nix b/devenv.nix index 9c2006825..bd811f315 100644 --- a/devenv.nix +++ b/devenv.nix @@ -30,6 +30,9 @@ let pnpmTaskHelpersScript = pkgs.writeText "pnpm-task-helpers.sh" ( builtins.readFile ./nix/devenv-modules/tasks/shared/pnpm-task-helpers.sh ); + buck2RootedNixConfigScript = pkgs.writeText "buck2-rooted-nix-config.sh" ( + builtins.readFile ./nix/devenv-modules/tasks/shared/buck2-rooted-nix-config.sh + ); rustCrates = [ { name = "otelite"; @@ -103,6 +106,14 @@ let entry = "packages/@overeng/buck2-launcher/src/cli.ts"; }; buck2Task = "${buck2SourceCli}/bin/buck2-task"; + megarepoPnpmDeps = repoFlake.packages.${currentSystem}."megarepo-pnpm-deps"; + opentuiCoreNative = import ./nix/opentui-core-native.nix { inherit pkgs; }; + opentuiCorePrimary = opentuiCoreNative.package; + opentuiCoreMusl = + if builtins.length opentuiCoreNative.packages > 1 then + (builtins.elemAt opentuiCoreNative.packages 1).package + else + opentuiCorePrimary; buck2Stage0Resolver = mkSourceCli { name = "buck2-stage0-config"; entry = "packages/@overeng/buck2-tools/src/stage0-config-cli.ts"; @@ -372,7 +383,20 @@ let "context/otel-scrape/telemetry-registry.json" "genie/buck2/*.ts" "packages/@overeng/buck2-tools/src/**/*.ts" + "packages/@overeng/otel-scrape/Cargo.toml" + "packages/@overeng/otel-scrape/src/*.rs" + "packages/@overeng/otel-scrape/src/**/*.rs" + "rust/Cargo.lock" + "rust/Cargo.toml" + "rust/reindeer.bzl" + "rust/reindeer.toml" + "rust/third-party/BUCK" + "rust/third-party/fixups/**/*.toml" "packages/@overeng/tui-core/buck2/target.ts" + "packages/@overeng/megarepo/bin/**/*.ts" + "packages/@overeng/megarepo/buck2/**/*.ts" + "packages/@overeng/megarepo/src/**/*.ts" + "packages/@overeng/megarepo/src/**/*.tsx" "packages/@overeng/tui-core/src/**/*.ts" "packages/@overeng/tui-core/src/**/*.tsx" "packages/@overeng/tui-core/src/**/*.cts" @@ -395,8 +419,6 @@ in # composes with the full stack above without importing it a second time. (import ./nix/devenv-modules/observability.nix { project = "effect-utils"; - # Shell-entry setup is intentionally absent. Profile an instantiated, - # non-mutating task so check:all retains its trace integrity gate. profile = { name = "genie-check"; task = "genie:check"; @@ -518,9 +540,6 @@ in # pnpm, Genie, megarepo state, and the repository revision. runOnEnterShell = false; requiredTasks = [ ]; - # Reuse the Genie semantic-input SSOT in the cheap Git-index outer - # fingerprint so a warm shell cannot bypass projection invalidation. - extraFingerprintGlobs = genieExtraInputGlobs; # Keep shell entry resilient (R12): optional tasks run via @complete. # Ordering ensures source CLIs have deps before use. optionalTasks = [ @@ -793,6 +812,8 @@ in buck2_stage0_config="$(${buck2Stage0Resolve})" exec ${buck2Task} \ --evidence-dir "$root/tmp/buck2-evidence" \ + --repository-revision "$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" \ + --execution-platform ${lib.escapeShellArg currentSystem} \ --print-command \ -- build --config-file "$buck2_stage0_config" //:buck2_foundation //:portable_toolchain_evidence --local-only --no-remote-cache ''; @@ -807,6 +828,8 @@ in buck2_stage0_config="$(${buck2Stage0Resolve})" exec ${buck2Task} \ --evidence-dir "$root/tmp/buck2-evidence" \ + --repository-revision "$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" \ + --execution-platform ${lib.escapeShellArg currentSystem} \ --print-command \ -- build --config-file "$buck2_stage0_config" \ //:buck2_foundation \ @@ -823,14 +846,109 @@ in root="''${DEVENV_ROOT:-$PWD}" buck2_stage0_config="$(${buck2Stage0Resolve})" export AWK_BIN=${pkgs.gawk}/bin/awk + export CP_BIN=${pkgs.coreutils}/bin/cp + export DD_BIN=${pkgs.coreutils}/bin/dd + export GREP_BIN=${pkgs.gnugrep}/bin/grep export JQ_BIN=${pkgs.jq}/bin/jq + export MKTEMP_BIN=${pkgs.coreutils}/bin/mktemp export NIX_BIN=${pkgs.nix}/bin/nix + export BUCK2_REPOSITORY_REVISION="$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" + export BUCK2_EXECUTION_PLATFORM=${lib.escapeShellArg currentSystem} + export RM_BIN=${pkgs.coreutils}/bin/rm export BUCK2_STAGE0_CONFIG="$buck2_stage0_config" exec ${pkgs.bash}/bin/bash scripts/buck2-package-e2e.sh \ "$root" ${buck2Task} //packages/@overeng/tui-core:typescript_input_plan ''; }; + tasks."buck2:build:megarepo" = { + description = "Build the mr product from its exact Buck TypeScript graph"; + after = [ "genie:run" ]; + exec = trace.exec "buck2:build:megarepo" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + exec ${buck2Task} \ + --evidence-dir "$root/tmp/buck2-evidence" \ + --repository-revision "$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" \ + --execution-platform ${lib.escapeShellArg currentSystem} \ + --print-command -- build \ + --config-file "$buck2_stage0_config" \ + -c buck2_nix.bun=${pkgs.bun}/bin/bun \ + -c buck2_nix.tsgo=${effectTsgo}/bin/tsgo \ + -c buck2_nix.patchelf=${pkgs.patchelf}/bin/patchelf \ + -c buck2_nix.megarepo_deps=${megarepoPnpmDeps} \ + -c buck2_nix.opentui_glibc=${opentuiCorePrimary} \ + -c buck2_nix.opentui_musl=${opentuiCoreMusl} \ + //packages/@overeng/megarepo:mr --local-only --no-remote-cache + ''; + }; + + tasks."buck2:test:typescript-product" = { + description = "Test the Python-free TypeScript product tool"; + exec = trace.exec "buck2:test:typescript-product" '' + set -euo pipefail + cd rust + exec cargo test --locked --package buck2-typescript-product + ''; + }; + + tasks."buck2:e2e:megarepo-contract" = { + description = "Build mr and pass its emitted descriptor through the canonical Nix contract"; + after = [ "genie:run" ]; + exec = trace.exec "buck2:e2e:megarepo-contract" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + export BUCK2_PRODUCT_NIXPKGS=${repoFlake.inputs.nixpkgs} + export AWK_BIN=${pkgs.gawk}/bin/awk + export CP_BIN=${pkgs.coreutils}/bin/cp + export DD_BIN=${pkgs.coreutils}/bin/dd + export GREP_BIN=${pkgs.gnugrep}/bin/grep + export JQ_BIN=${pkgs.jq}/bin/jq + export MKTEMP_BIN=${pkgs.coreutils}/bin/mktemp + export NIX_BIN=${pkgs.nix}/bin/nix + export RM_BIN=${pkgs.coreutils}/bin/rm + exec ${pkgs.bash}/bin/bash scripts/buck2-megarepo-product-e2e.sh \ + "$root" ${buck2Task} //packages/@overeng/megarepo:mr \ + --config-file "$buck2_stage0_config" \ + -c buck2_nix.bun=${pkgs.bun}/bin/bun \ + -c buck2_nix.tsgo=${effectTsgo}/bin/tsgo \ + -c buck2_nix.patchelf=${pkgs.patchelf}/bin/patchelf \ + -c buck2_nix.megarepo_deps=${megarepoPnpmDeps} \ + -c buck2_nix.opentui_glibc=${opentuiCorePrimary} \ + -c buck2_nix.opentui_musl=${opentuiCoreMusl} + ''; + }; + + tasks."buck2:benchmark:megarepo" = { + description = "Measure warm, role-excluded, relevant, and coarse mr Buck invalidation boundaries"; + after = [ "genie:run" ]; + exec = trace.exec "buck2:benchmark:megarepo" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + output="$root/tmp/buck2-benchmark/megarepo-mr.jsonl" + ${pkgs.nodejs}/bin/node scripts/buck2-benchmark/benchmark.mjs \ + --execute --in-place --buck-incremental-only --buck-bin ${pkgs.buck2}/bin/buck2 \ + --buck-target //packages/@overeng/megarepo:mr \ + --buck-config-file "$buck2_stage0_config" \ + --buck-config buck2_nix.bun=${pkgs.bun}/bin/bun \ + --buck-config buck2_nix.tsgo=${effectTsgo}/bin/tsgo \ + --buck-config buck2_nix.patchelf=${pkgs.patchelf}/bin/patchelf \ + --buck-config buck2_nix.megarepo_deps=${megarepoPnpmDeps} \ + --buck-config buck2_nix.opentui_glibc=${opentuiCorePrimary} \ + --buck-config buck2_nix.opentui_musl=${opentuiCoreMusl} \ + --work-contract megarepo-cli-product/no-equivalent-devenv-lane/v1 \ + --relevant-path packages/@overeng/megarepo/src/lib/version.ts \ + --declared-unreachable-path packages/@overeng/megarepo/src/buck2-declared-unreachable-fixture.ts \ + --irrelevant-path packages/@overeng/megarepo/src/lib/ref.unit.test.ts \ + --runs 7 --warmups 2 --isolation-dir megarepo-mr-benchmark \ + --output "$output" + exec ${pkgs.nodejs}/bin/node scripts/buck2-benchmark/assert-invalidation.mjs "$output" + ''; + }; + tasks."buck2:nix-bridge:check" = { description = "Check the strict build-product contract, Nix tool export, and fail-closed artifact importer"; exec = trace.exec "buck2:nix-bridge:check" '' @@ -929,6 +1047,7 @@ in description = "Prove the Nix-authored Rust toolchain, target, and execution-platform contract"; exec = trace.exec "buck2:rust-musl:check" '' set -euo pipefail + ${pkgs.bash}/bin/bash nix/workspace-tools/lib/tests/buck2-rust-toolchain-identity-static.sh "$PWD" isolation="rust-musl-check-$$-$RANDOM" stderr_file="$(${pkgs.coreutils}/bin/mktemp "''${TMPDIR:-/tmp}/buck2-rust-musl-check.XXXXXX")" toolchain_root_dir="" @@ -970,6 +1089,7 @@ in --config-file "$toolchain_config" --target-platforms //buck2/platforms:target_x86_64_linux_musl_static //buck2/rust:static_hello + //buck2/rust:x86_64_linux_musl_config_integrity --local-only --no-remote-cache ) @@ -985,6 +1105,24 @@ in exit 1 } + # The false narrow identity must also fail through Prelude's conventional + # Rust provider used by the real OTEL product, not only static_hello. + if buck2_with_toolchain_root \ + --isolation-dir "$isolation" \ + build --config-file "$toolchain_config" \ + --target-platforms //buck2/platforms:target_x86_64_linux_musl_static \ + //packages/@overeng/otel-scrape:product \ + --config rust_toolchain.compile_identity=sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ + --local-only --no-remote-cache \ + >/dev/null 2>"$stderr_file"; then + echo "buck2:rust-musl:check: false OTEL compile identity unexpectedly admitted" >&2 + exit 1 + fi + ${pkgs.gnugrep}/bin/grep -F "toolchain identity digest mismatch" "$stderr_file" >/dev/null || { + echo "buck2:rust-musl:check: missing OTEL compile-identity rejection" >&2 + exit 1 + } + if buck2_with_toolchain_root "''${common[@]}" \ --config rust_toolchain.target_platform=//buck2/platforms:target_x86_64_linux_glibc_dynamic \ >/dev/null 2>"$stderr_file"; then @@ -996,9 +1134,235 @@ in exit 1 } - buck2_with_toolchain_root "''${common[@]}" - identity="$(${pkgs.gawk}/bin/awk '$1 == "toolchain_identity" { print $3 }' "$toolchain_config")" - echo "buck2:rust-musl:check: PASS identity=$identity" + if buck2_with_toolchain_root "''${common[@]}" \ + --config rust_toolchain.rustc=/nix/store/00000000000000000000000000000000-mismatch/bin/rustc \ + >/dev/null 2>"$stderr_file"; then + echo "buck2:rust-musl:check: stale toolchain identity unexpectedly admitted" >&2 + exit 1 + fi + ${pkgs.gnugrep}/bin/grep -F "Rust config-integrity material does not match" "$stderr_file" >/dev/null || { + echo "buck2:rust-musl:check: missing identity-material rejection" >&2 + exit 1 + } + + # Destructive control: an omitted configured executable must fail before + # analysis can accept the Nix-authored aggregate identity. + if buck2_with_toolchain_root "''${common[@]}" \ + --config rust_toolchain.ar= \ + >/dev/null 2>"$stderr_file"; then + echo "buck2:rust-musl:check: omitted archiver unexpectedly admitted" >&2 + exit 1 + fi + ${pkgs.gnugrep}/bin/grep -F "ar must be an absolute Nix store executable" "$stderr_file" >/dev/null || { + echo "buck2:rust-musl:check: missing omitted-archiver rejection" >&2 + exit 1 + } + + if buck2_with_toolchain_root "''${common[@]}" \ + --config rust_toolchain.compile_identity=sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ + >/dev/null 2>"$stderr_file"; then + echo "buck2:rust-musl:check: false toolchain identity unexpectedly admitted" >&2 + exit 1 + fi + ${pkgs.gnugrep}/bin/grep -F "toolchain identity digest mismatch" "$stderr_file" >/dev/null || { + echo "buck2:rust-musl:check: missing recomputed identity rejection" >&2 + exit 1 + } + + if buck2_with_toolchain_root "''${common[@]}" \ + --config rust_toolchain.config_integrity_identity=sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ + >/dev/null 2>"$stderr_file"; then + echo "buck2:rust-musl:check: false config-integrity identity unexpectedly admitted" >&2 + exit 1 + fi + ${pkgs.gnugrep}/bin/grep -F "toolchain identity digest mismatch" "$stderr_file" >/dev/null || { + echo "buck2:rust-musl:check: missing config-integrity digest rejection" >&2 + exit 1 + } + + build_output="$(buck2_with_toolchain_root "''${common[@]}" --show-full-output)" + binary="$(printf '%s\n' "$build_output" | ${pkgs.gawk}/bin/awk \ + '$1 == "root//buck2/rust:static_hello" { print $2; exit }')" + [ -f "$binary" ] || { + echo "buck2:rust-musl:check: Buck did not report the static binary output" >&2 + exit 1 + } + ${pkgs.binutils}/bin/readelf -h "$binary" \ + | ${pkgs.gnugrep}/bin/grep -F "Machine:" \ + | ${pkgs.gnugrep}/bin/grep -F "X86-64" >/dev/null || { + echo "buck2:rust-musl:check: output is not x86_64 ELF" >&2 + exit 1 + } + if ${pkgs.binutils}/bin/readelf -l "$binary" | ${pkgs.gnugrep}/bin/grep -F " INTERP " >/dev/null; then + echo "buck2:rust-musl:check: output declares a dynamic interpreter" >&2 + exit 1 + fi + if ${pkgs.binutils}/bin/readelf -d "$binary" 2>/dev/null | ${pkgs.gnugrep}/bin/grep -F "(NEEDED)" >/dev/null; then + echo "buck2:rust-musl:check: output declares a dynamic dependency" >&2 + exit 1 + fi + if ${pkgs.gnugrep}/bin/grep -aF "/nix/store/" "$binary" >/dev/null; then + echo "buck2:rust-musl:check: output embeds a Nix store reference" >&2 + exit 1 + fi + sterile_output="$(${pkgs.coreutils}/bin/env -i PATH=/nonexistent "$binary")" + [ "$sterile_output" = "buck2-rust-musl-ok" ] || { + echo "buck2:rust-musl:check: output failed under a sterile runtime environment" >&2 + exit 1 + } + identity="$(${pkgs.gawk}/bin/awk '$1 == "compile_identity" { print $3 }' "$toolchain_config")" + echo "buck2:rust-musl:check: PASS compile_identity=$identity static=true store_refs=none sterile=true" + ''; + }; + + tasks."buck2:rust-deps:generate" = { + description = "Regenerate the central Reindeer graph from the root Cargo resolution domain"; + exec = trace.exec "buck2:rust-deps:generate" '' + set -euo pipefail + exec ${pkgs.reindeer}/bin/reindeer \ + --cargo-path ${pkgs.cargo}/bin/cargo \ + --rustc-path ${pkgs.rustc}/bin/rustc \ + --config rust/reindeer.toml buckify + ''; + }; + + tasks."buck2:rust-deps:check" = { + description = "Verify the central Reindeer graph is fresh"; + exec = trace.exec "buck2:rust-deps:check" '' + set -euo pipefail + generated=rust/third-party/BUCK + candidate="$(${pkgs.coreutils}/bin/mktemp)" + trap '${pkgs.coreutils}/bin/rm -f "$candidate"' EXIT + ${pkgs.reindeer}/bin/reindeer \ + --cargo-path ${pkgs.cargo}/bin/cargo \ + --rustc-path ${pkgs.rustc}/bin/rustc \ + --config rust/reindeer.toml buckify --stdout >"$candidate" + ${pkgs.diffutils}/bin/cmp "$generated" "$candidate" || { + echo "buck2:rust-deps:check: generated Reindeer graph is stale" >&2 + exit 1 + } + ''; + }; + + tasks."buck2:otel-scrape:product" = lib.mkIf (currentSystem == "x86_64-linux") { + description = "Build the static otel-scrape product without invoking Cargo in Buck actions"; + after = [ + "genie:run" + "buck2:rust-deps:check" + ]; + exec = trace.exec "buck2:otel-scrape:product" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + source ${buck2RootedNixConfigScript} + export BUCK2_ROOTED_NIX_BIN=${pkgs.nix}/bin/nix + buck2_root_nix_config toolchain_config .#buck2-rust-musl-toolchain-config + ${buck2Task} \ + --evidence-dir "$root/tmp/buck2-evidence" \ + --repository-revision "$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" \ + --execution-platform ${lib.escapeShellArg currentSystem} \ + --print-command \ + -- build \ + --config-file "$buck2_stage0_config" \ + --config-file "$toolchain_config" \ + --target-platforms //buck2/platforms:target_x86_64_linux_musl_static \ + //packages/@overeng/otel-scrape:product \ + toolchains//:conventional_rust_cxx_execution_probe \ + --local-only --no-remote-cache + ${buck2Task} \ + --evidence-dir "$root/tmp/buck2-evidence" \ + --repository-revision "$(${pkgs.git}/bin/git -C "$root" rev-parse HEAD)" \ + --execution-platform ${lib.escapeShellArg currentSystem} \ + --print-command \ + -- test \ + --config-file "$buck2_stage0_config" \ + --config-file "$toolchain_config" \ + --target-platforms //buck2/platforms:target_x86_64_linux_musl_static \ + //packages/@overeng/otel-scrape:unit \ + --local-only --no-remote-cache + ''; + }; + + tasks."buck2:rooted-nix-config:check" = { + description = "Prove Buck task Nix configs remain GC-rooted for child lifetime"; + exec = trace.exec "buck2:rooted-nix-config:check" '' + exec ${pkgs.bash}/bin/bash \ + nix/devenv-modules/tasks/shared/tests/buck2-rooted-nix-config.test.sh "$PWD" + ''; + }; + + tasks."buck2:otel-scrape:benchmark" = lib.mkIf (currentSystem == "x86_64-linux") { + description = "Measure warm OTEL product invalidation with Buck action/materialization evidence"; + after = [ + "genie:run" + "buck2:rust-deps:check" + ]; + exec = trace.exec "buck2:otel-scrape:benchmark" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + source ${buck2RootedNixConfigScript} + export BUCK2_ROOTED_NIX_BIN=${pkgs.nix}/bin/nix + buck2_root_nix_config toolchain_config .#buck2-rust-musl-toolchain-config + ${pkgs.nodejs}/bin/node scripts/buck2-benchmark/benchmark.mjs \ + --execute \ + --in-place \ + --buck-incremental-only \ + --assert-buck-invalidation \ + --expected-relevant-actions 2 \ + --buck-bin ${buck2Machine}/bin/buck2 \ + --buck-config-file "$buck2_stage0_config" \ + --buck-config-file "$toolchain_config" \ + --buck-target //packages/@overeng/otel-scrape:product \ + --buck-target-platform //buck2/platforms:target_x86_64_linux_musl_static \ + --work-contract effect-utils/otel-scrape-native-product-v1 \ + --relevant-path packages/@overeng/otel-scrape/src/lib.rs \ + --irrelevant-path context/dependency-materialization/intuition.md + ''; + }; + + tasks."buck2:otel-scrape:nix-import-smoke" = lib.mkIf (currentSystem == "x86_64-linux") { + description = "Smoke-test exact Buck product import with a self-derived descriptor identity"; + after = [ + "genie:run" + "buck2:rust-deps:check" + ]; + exec = trace.exec "buck2:otel-scrape:nix-import-smoke" '' + set -euo pipefail + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + source ${buck2RootedNixConfigScript} + export BUCK2_ROOTED_NIX_BIN=${pkgs.nix}/bin/nix + buck2_root_nix_config toolchain_config .#buck2-rust-musl-toolchain-config + export BUCK2_BIN=${buck2Machine}/bin/buck2 + export NIX_BIN=${pkgs.nix}/bin/nix + export JQ_BIN=${pkgs.jq}/bin/jq + export AWK_BIN=${pkgs.gawk}/bin/awk + ${pkgs.bash}/bin/bash scripts/buck2-otel-scrape-nix-admission.sh \ + smoke "$buck2_stage0_config" "$toolchain_config" + ''; + }; + + tasks."buck2:otel-scrape:nix-admit" = lib.mkIf (currentSystem == "x86_64-linux") { + description = "Admit the exact Buck product using an externally supplied descriptor identity"; + after = [ + "genie:run" + "buck2:rust-deps:check" + ]; + exec = trace.exec "buck2:otel-scrape:nix-admit" '' + set -euo pipefail + : "''${BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST:?buck2:otel-scrape:nix-admit requires BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST}" + root="''${DEVENV_ROOT:-$PWD}" + buck2_stage0_config="$(${buck2Stage0Resolve})" + source ${buck2RootedNixConfigScript} + export BUCK2_ROOTED_NIX_BIN=${pkgs.nix}/bin/nix + buck2_root_nix_config toolchain_config .#buck2-rust-musl-toolchain-config + export BUCK2_BIN=${buck2Machine}/bin/buck2 + export NIX_BIN=${pkgs.nix}/bin/nix + export JQ_BIN=${pkgs.jq}/bin/jq + export AWK_BIN=${pkgs.gawk}/bin/awk + ${pkgs.bash}/bin/bash scripts/buck2-otel-scrape-nix-admission.sh \ + admit "$buck2_stage0_config" "$toolchain_config" ''; }; @@ -1006,16 +1370,24 @@ in description = "Run Buck2 foundation, invalidation, platform, Nix bridge, and benchmark gates"; after = [ "buck2:build:foundation" + "buck2:build:megarepo" + "buck2:e2e:megarepo-contract" "buck2:test:foundation" + "buck2:test:typescript-product" "buck2:foundation:graph-check" "buck2:e2e:tui-core" "buck2:nix-bridge:check" "buck2:benchmark:check" + "buck2:benchmark:megarepo" "buck2:invalidation:e2e" "buck2:platform:check" ] ++ lib.optionals (currentSystem == "x86_64-linux") [ "buck2:rust-musl:check" + "buck2:rooted-nix-config:check" + "buck2:otel-scrape:product" + "buck2:otel-scrape:nix-import-smoke" + "buck2:otel-scrape:benchmark" ]; }; diff --git a/flake.nix b/flake.nix index b3e4b6636..a8249d83c 100644 --- a/flake.nix +++ b/flake.nix @@ -85,8 +85,14 @@ (import ./nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix { inherit pkgs; } { # The matching prebuilt archive supplies rustc and the musl # standard library without rebuilding Rust/LLVM. + clippyDriver = "${pkgs.clippy}/bin/clippy-driver"; rustc = "${rustPackageSet.packages.prebuilt.rustc}/bin/rustc"; + rustdoc = "${rustPackageSet.packages.prebuilt.rustc}/bin/rustdoc"; linker = "${cross.stdenv.cc}/bin/${cross.stdenv.cc.targetPrefix}cc"; + cxx = "${cross.stdenv.cc}/bin/${cross.stdenv.cc.targetPrefix}c++"; + binutils = cross.binutils; + python = "${pkgs.python3}/bin/python3"; + toolPath = "${pkgs.bash}/bin:${pkgs.coreutils}/bin"; }).config else null; diff --git a/nix/buck2-stage0-tools.nix b/nix/buck2-stage0-tools.nix index eeb81cad1..88db82504 100644 --- a/nix/buck2-stage0-tools.nix +++ b/nix/buck2-stage0-tools.nix @@ -46,6 +46,11 @@ let packageRoot = workspaceRoot + "/buck2-tools/package-evidence"; workspaceMember = "buck2-tools/package-evidence"; }; + typescript-product = { + package = "buck2-typescript-product"; + packageRoot = workspaceRoot + "/buck2-tools/typescript-product"; + workspaceMember = "buck2-tools/typescript-product"; + }; portable-toolchain = { package = "buck2-portable-toolchain"; packageRoot = workspaceRoot + "/buck2-tools/portable-toolchain"; @@ -108,6 +113,7 @@ in ) toolDefinitions; closure-tool = mkTool toolDefinitions.closure-tool; package-evidence = mkTool toolDefinitions.package-evidence; + typescript-product = mkTool toolDefinitions.typescript-product; portable-toolchain = mkTool toolDefinitions.portable-toolchain; portable-toolchain-fixture = mkTool toolDefinitions.portable-toolchain-fixture; } diff --git a/nix/devenv-modules/tasks/shared/buck2-rooted-nix-config.sh b/nix/devenv-modules/tasks/shared/buck2-rooted-nix-config.sh new file mode 100644 index 000000000..0a478ea46 --- /dev/null +++ b/nix/devenv-modules/tasks/shared/buck2-rooted-nix-config.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# Source this file, then call buck2_root_nix_config VARIABLE FLAKE_REF. +# The resulting config and its closure remain GC-rooted until the caller exits. +buck2_rooted_nix_config_dir="" + +buck2_rooted_nix_config_cleanup() { + if [ -n "$buck2_rooted_nix_config_dir" ]; then + "${BUCK2_ROOTED_RM_BIN:-rm}" -f "$buck2_rooted_nix_config_dir/config" + "${BUCK2_ROOTED_RMDIR_BIN:-rmdir}" "$buck2_rooted_nix_config_dir" 2>/dev/null || true + buck2_rooted_nix_config_dir="" + fi +} + +buck2_rooted_nix_config_signal() { + local signal="$1" + buck2_rooted_nix_config_cleanup + case "$signal" in + INT) exit 130 ;; + TERM) exit 143 ;; + *) exit 128 ;; + esac +} + +buck2_root_nix_config() { + local output_variable="$1" + local flake_ref="$2" + local root target + + [ -z "$buck2_rooted_nix_config_dir" ] || { + echo "buck2-rooted-nix-config: one rooted config per task invocation" >&2 + return 64 + } + root="$(${BUCK2_ROOTED_MKTEMP_BIN:-mktemp} -d "${TMPDIR:-/tmp}/buck2-toolchain-root.XXXXXX")" + buck2_rooted_nix_config_dir="$root" + trap buck2_rooted_nix_config_cleanup EXIT + trap 'buck2_rooted_nix_config_signal INT' INT + trap 'buck2_rooted_nix_config_signal TERM' TERM + + target="$(${BUCK2_ROOTED_NIX_BIN:-nix} build \ + --out-link "$root/config" \ + --print-out-paths \ + "$flake_ref")" || return + case "$target" in + *$'\n'*) echo "buck2-rooted-nix-config: build returned multiple store paths" >&2; return 1 ;; + /nix/store/*) ;; + *) echo "buck2-rooted-nix-config: build returned a non-store path" >&2; return 1 ;; + esac + [ -L "$root/config" ] || { + echo "buck2-rooted-nix-config: Nix did not create the requested GC root" >&2 + return 1 + } + [ "$(${BUCK2_ROOTED_READLINK_BIN:-readlink} -f "$root/config")" = "$target" ] || { + echo "buck2-rooted-nix-config: GC root does not bind the reported config" >&2 + return 1 + } + [ -f "$target" ] || { + echo "buck2-rooted-nix-config: rooted config is not a regular file" >&2 + return 1 + } + + printf -v "$output_variable" '%s' "$target" + export BUCK2_ROOTED_NIX_CONFIG_ROOT="$root/config" +} diff --git a/nix/devenv-modules/tasks/shared/tests/buck2-rooted-nix-config.test.sh b/nix/devenv-modules/tasks/shared/tests/buck2-rooted-nix-config.test.sh new file mode 100644 index 000000000..199fee3d2 --- /dev/null +++ b/nix/devenv-modules/tasks/shared/tests/buck2-rooted-nix-config.test.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.." && pwd -P)}" +helper="$repo_root/nix/devenv-modules/tasks/shared/buck2-rooted-nix-config.sh" +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT + +mkdir -p "$tmp/bin" +target="$(readlink -f "$(command -v bash)")" +cat >"$tmp/bin/nix" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +out_link="" +while [ "$#" -gt 0 ]; do + case "$1" in + --out-link) out_link="$2"; shift 2 ;; + *) shift ;; + esac +done +ln -s "$BUCK2_ROOTED_TEST_TARGET" "$out_link" +printf '%s\n' "$BUCK2_ROOTED_TEST_TARGET" +EOF +chmod +x "$tmp/bin/nix" + +export BUCK2_ROOTED_TEST_TARGET="$target" +export BUCK2_ROOTED_NIX_BIN="$tmp/bin/nix" +export BUCK2_ROOTED_MKTEMP_BIN="$(command -v mktemp)" +export BUCK2_ROOTED_READLINK_BIN="$(command -v readlink)" +export BUCK2_ROOTED_RM_BIN="$(command -v rm)" +export BUCK2_ROOTED_RMDIR_BIN="$(command -v rmdir)" + +( + set -euo pipefail + source "$helper" + buck2_root_nix_config config .#fixture + [ "$config" = "$target" ] + [ -L "$BUCK2_ROOTED_NIX_CONFIG_ROOT" ] + [ "$(readlink -f "$BUCK2_ROOTED_NIX_CONFIG_ROOT")" = "$config" ] + # This is the concurrent-GC seam: the root must remain present for the whole + # simulated Buck child, not merely until `nix build` returns. + sh -c '[ -L "$BUCK2_ROOTED_NIX_CONFIG_ROOT" ] && [ -f "$1" ]' sh "$config" + printf '%s\n' "$BUCK2_ROOTED_NIX_CONFIG_ROOT" >"$tmp/root-path" +) +[ ! -e "$(cat "$tmp/root-path")" ] + +set +e +BUCK2_ROOTED_SIGNAL_PATH="$tmp/signal-root-path" \ + bash -c ' + set -euo pipefail + source "$1" + buck2_root_nix_config config .#fixture + printf "%s\n" "$BUCK2_ROOTED_NIX_CONFIG_ROOT" >"$BUCK2_ROOTED_SIGNAL_PATH" + kill -TERM "$BASHPID" + ' bash "$helper" +signal_status="$?" +set -e +[ "$signal_status" -eq 143 ] +[ ! -e "$(cat "$tmp/signal-root-path")" ] + +echo "buck2-rooted-nix-config-test: PASS rooted_during_child=true cleaned_after_exit=true cleaned_after_signal=true" diff --git a/nix/workspace-tools/lib/buck2-artifact-import.nix b/nix/workspace-tools/lib/buck2-artifact-import.nix index 6a29e6a12..7444aa876 100644 --- a/nix/workspace-tools/lib/buck2-artifact-import.nix +++ b/nix/workspace-tools/lib/buck2-artifact-import.nix @@ -2,7 +2,10 @@ # # Shape validation is not runtime proof. Each accepted tagged runtime dispatches # to an exact inspector; all other runtime kinds remain fail closed. -{ pkgs }: +{ + pkgs, + inspectElfStatic ? import ./buck2-runtime-inspect-elf-static.nix { inherit pkgs; }, +}: let lib = pkgs.lib; @@ -24,6 +27,13 @@ let }; checkedPlatform = checkedDescriptor.platform; runtimeKind = checkedDescriptor.runtime.kind; + runtimeInspector = + if runtimeKind == "elf-dynamic" then + inspectElfDynamic + else if runtimeKind == "self-contained" then + inspectElfStatic + else + throw "buck2-artifact-import: runtime inspector is not available for ${runtimeKind}"; payload = checkedDescriptor.payload; fetchedArtifact = if url == null then @@ -48,42 +58,39 @@ assert lib.assertMsg ( assert lib.assertMsg ( url != null || artifact != null ) "buck2-artifact-import: a published URL or declared artifact path is required"; -if runtimeKind != "elf-dynamic" then - throw "buck2-artifact-import: runtime inspector is not available for ${runtimeKind}" -else - pkgs.runCommand "${checkedDescriptor.name}-buck2-import" - { - nativeBuildInputs = [ pkgs.openssl ]; - allowedReferences = [ ]; - passthru = { - descriptorDigest = expectedDescriptorDigest; - inherit checkedDescriptor; - }; +pkgs.runCommand "${checkedDescriptor.name}-buck2-import" + { + nativeBuildInputs = [ pkgs.openssl ]; + allowedReferences = [ ]; + passthru = { + descriptorDigest = expectedDescriptorDigest; + inherit checkedDescriptor; + }; + } + '' + set -euo pipefail + archive=${lib.escapeShellArg (toString fetchedArtifact)} + actual_size="$(${pkgs.coreutils}/bin/stat --format=%s "$archive")" + [ "$actual_size" = ${lib.escapeShellArg (toString payload.sizeBytes)} ] || { + echo "buck2-artifact-import: payload size mismatch: expected ${toString payload.sizeBytes}, got $actual_size" >&2 + exit 1 + } + actual_digest="sha256-$(${pkgs.openssl}/bin/openssl dgst -sha256 -binary "$archive" \ + | ${pkgs.openssl}/bin/openssl base64 -A)" + [ "$actual_digest" = ${lib.escapeShellArg payload.digest.sri} ] || { + echo "buck2-artifact-import: payload digest mismatch" >&2 + exit 1 } - '' - set -euo pipefail - archive=${lib.escapeShellArg (toString fetchedArtifact)} - actual_size="$(${pkgs.coreutils}/bin/stat --format=%s "$archive")" - [ "$actual_size" = ${lib.escapeShellArg (toString payload.sizeBytes)} ] || { - echo "buck2-artifact-import: payload size mismatch: expected ${toString payload.sizeBytes}, got $actual_size" >&2 - exit 1 - } - actual_digest="sha256-$(${pkgs.openssl}/bin/openssl dgst -sha256 -binary "$archive" \ - | ${pkgs.openssl}/bin/openssl base64 -A)" - [ "$actual_digest" = ${lib.escapeShellArg payload.digest.sri} ] || { - echo "buck2-artifact-import: payload digest mismatch" >&2 - exit 1 - } - ${scan} archive "$archive" - mkdir -p "$out" - ${pkgs.gnutar}/bin/tar --extract --file "$archive" --directory "$out" \ - --no-same-owner --no-same-permissions - ${scan} tree "$out" - ${inspectElfDynamic} ${descriptorFile} "$out" + ${scan} archive "$archive" + mkdir -p "$out" + ${pkgs.gnutar}/bin/tar --extract --file "$archive" --directory "$out" \ + --no-same-owner --no-same-permissions + ${scan} tree "$out" + ${runtimeInspector} ${descriptorFile} "$out" - ${pkgs.findutils}/bin/find "$out" -type d -exec chmod 0555 {} + - while IFS= read -r -d "" file; do - if [ -x "$file" ]; then chmod 0555 "$file"; else chmod 0444 "$file"; fi - done < <(${pkgs.findutils}/bin/find "$out" -type f -print0) - '' + ${pkgs.findutils}/bin/find "$out" -type d -exec chmod 0555 {} + + while IFS= read -r -d "" file; do + if [ -x "$file" ]; then chmod 0555 "$file"; else chmod 0444 "$file"; fi + done < <(${pkgs.findutils}/bin/find "$out" -type f -print0) + '' diff --git a/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix b/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix new file mode 100644 index 000000000..098bb7d73 --- /dev/null +++ b/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix @@ -0,0 +1,74 @@ +# Inspect an extracted buck-build-product/v1 self-contained ELF payload without +# rewriting it. The descriptor is a claim; readelf output is the observation. +{ + pkgs, + readelf ? "${pkgs.binutils}/bin/readelf", +}: + +pkgs.writeShellScript "buck2-runtime-inspect-elf-static" '' + set -euo pipefail + export LC_ALL=C + + fail() { + echo "buck2-runtime-inspect-elf-static: FATAL - $*" >&2 + exit 1 + } + + [ "$#" -eq 2 ] || fail "usage: $0 DESCRIPTOR_JSON EXTRACTED_ROOT" + descriptor="$1" + root="$2" + [ -f "$descriptor" ] || fail "descriptor does not exist" + [ -d "$root" ] || fail "extracted root does not exist" + + [ "$(${pkgs.jq}/bin/jq -r '.runtime.kind' "$descriptor")" = self-contained ] \ + || fail "descriptor runtime kind must be self-contained" + [ "$(${pkgs.jq}/bin/jq -r '.runtime.inspectionContract' "$descriptor")" = elf-static/v1 ] \ + || fail "unsupported inspection contract" + ${pkgs.jq}/bin/jq -e \ + '.platform == { os: "linux", architecture: "x86_64", abi: "musl" }' \ + "$descriptor" >/dev/null \ + || fail "static ELF inspector admits only linux/x86_64/musl" + + inspect_entrypoint() { + local relative="$1" + local executable="$root/$relative" + [ -f "$executable" ] && [ ! -L "$executable" ] \ + || fail "entrypoint must be a regular non-symlink file: $relative" + [ -x "$executable" ] || fail "entrypoint is not executable: $relative" + + local header actual_class actual_machine + if ! header="$(${readelf} --file-header "$executable")"; then + fail "readelf --file-header failed for $relative" + fi + actual_class="$(printf '%s\n' "$header" \ + | ${pkgs.gawk}/bin/awk -F: '$1 ~ /^[[:space:]]*Class$/ { sub(/^[[:space:]]+/, "", $2); print $2 }')" + [ "$actual_class" = ELF64 ] \ + || fail "ELF class mismatch for $relative: expected ELF64, got $actual_class" + actual_machine="$(printf '%s\n' "$header" \ + | ${pkgs.gawk}/bin/awk -F: '$1 ~ /^[[:space:]]*Machine$/ { sub(/^[[:space:]]+/, "", $2); print $2 }')" + [ "$actual_machine" = "Advanced Micro Devices X86-64" ] \ + || fail "ELF machine mismatch for $relative: expected x86_64, got $actual_machine" + + local program_headers + if ! program_headers="$(${readelf} --program-headers "$executable")"; then + fail "readelf --program-headers failed for $relative" + fi + if printf '%s\n' "$program_headers" \ + | ${pkgs.gnugrep}/bin/grep -Eq '^[[:space:]]*INTERP[[:space:]]'; then + fail "self-contained ELF declares an interpreter: $relative" + fi + + local dynamic_section + if ! dynamic_section="$(${readelf} --dynamic "$executable")"; then + fail "readelf --dynamic failed for $relative" + fi + if printf '%s\n' "$dynamic_section" \ + | ${pkgs.gnugrep}/bin/grep -Eq '\(NEEDED\)'; then + fail "self-contained ELF declares a shared-library dependency: $relative" + fi + } + + while IFS= read -r entrypoint; do + inspect_entrypoint "$entrypoint" + done < <(${pkgs.jq}/bin/jq -r '.entrypoints[]' "$descriptor") +'' diff --git a/nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix b/nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix index cd9b9964e..d015934cb 100644 --- a/nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix +++ b/nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix @@ -2,7 +2,21 @@ { rustc, + rustdoc ? "${builtins.dirOf (builtins.dirOf rustc)}/bin/rustdoc", + clippyDriver ? "${builtins.dirOf (builtins.dirOf rustc)}/bin/clippy-driver", linker, + cc ? linker, + cxx ? linker, + binutils, + ar ? "${binutils}/bin/ar", + dwp ? "${binutils}/bin/dwp", + nm ? "${binutils}/bin/nm", + objcopy ? "${binutils}/bin/objcopy", + objdump ? "${binutils}/bin/objdump", + ranlib ? "${binutils}/bin/ranlib", + strip ? "${binutils}/bin/strip", + python, + toolPath, targetTriple ? "x86_64-unknown-linux-musl", }: @@ -24,23 +38,66 @@ let echo "buck2-rust-toolchain-identity-verify: toolchain identity digest mismatch" >&2 exit 1 } + if [ "''${1-}" = "--stamp" ]; then + [ "$#" -eq 2 ] || { + echo "buck2-rust-toolchain-identity-verify: expected --stamp OUTPUT" >&2 + exit 64 + } + printf '%s\n' "$expected" > "$2" + exit 0 + fi exec "$@" ''; - # This ordered material is both hashed by Nix and reassembled by Buck from - # the supplied fields. A stale/mixed config cannot retain the old identity. - identityMaterial = builtins.concatStringsSep ";" [ + # Complete material detects a stale or spliced config. It is deliberately + # not an action key: actions use the narrow semantic material below. + configIntegrityMaterial = builtins.concatStringsSep ";" [ + "ar=${ar}" + "cc=${cc}" + "clippy_driver=${clippyDriver}" "contract=${contract}" + "cxx=${cxx}" + "dwp=${dwp}" "execution_platform=${executionPlatform}" "identity_verifier=${identityVerifier}" "linker=${linker}" + "nm=${nm}" + "objcopy=${objcopy}" + "objdump=${objdump}" + "python=${python}" + "ranlib=${ranlib}" "rustc=${rustc}" + "rustdoc=${rustdoc}" + "strip=${strip}" "target_platform=${targetPlatform}" "target_triple=${targetTriple}" + "tool_path=${toolPath}" ]; - identity = builtins.hashString "sha256" identityMaterial; + configIntegrityIdentity = builtins.hashString "sha256" configIntegrityMaterial; + + # Prelude Rust compilation receives these exact paths or claims. Product + # provenance uses this identity, so lint/docs/Python/unused binutils changes + # do not invalidate compile or packaging. + compileMaterial = builtins.concatStringsSep ";" [ + "ar=${ar}" + "cc=${cc}" + "contract=${contract}" + "cxx=${cxx}" + "execution_platform=${executionPlatform}" + "linker=${linker}" + "rustc=${rustc}" + "target_platform=${targetPlatform}" + "target_triple=${targetTriple}" + "tool_path=${toolPath}" + ]; + compileIdentity = builtins.hashString "sha256" compileMaterial; in { - inherit identity; + inherit + compileIdentity + compileMaterial + configIntegrityIdentity + configIntegrityMaterial + ; # One immutable file carries paths and semantic claims together. Buck still # enforces its configured target/execution constraints independently. @@ -53,10 +110,25 @@ in execution_platform = ${executionPlatform} identity_verifier = ${identityVerifier} linker = ${linker} + cc = ${cc} + cxx = ${cxx} + ar = ${ar} + dwp = ${dwp} + nm = ${nm} + objcopy = ${objcopy} + objdump = ${objdump} + ranlib = ${ranlib} + strip = ${strip} + python = ${python} + tool_path = ${toolPath} rustc = ${rustc} + rustdoc = ${rustdoc} + clippy_driver = ${clippyDriver} target_platform = ${targetPlatform} target_triple = ${targetTriple} - toolchain_identity_material = ${identityMaterial} - toolchain_identity = sha256:${identity} + config_integrity_material = ${configIntegrityMaterial} + config_integrity_identity = sha256:${configIntegrityIdentity} + compile_identity_material = ${compileMaterial} + compile_identity = sha256:${compileIdentity} ''; } diff --git a/nix/workspace-tools/lib/tests/buck2-bridge.nix b/nix/workspace-tools/lib/tests/buck2-bridge.nix index e36d23bd0..8af762ed0 100644 --- a/nix/workspace-tools/lib/tests/buck2-bridge.nix +++ b/nix/workspace-tools/lib/tests/buck2-bridge.nix @@ -166,6 +166,14 @@ let exec ${pkgs.binutils}/bin/readelf "$@" ''; + hiddenInterpreterReadelf = pkgs.writeShellScript "hidden-interpreter-readelf" '' + if [ "''${1-}" = --program-headers ]; then + printf '%s\n' 'There are no program headers in this file.' + exit 0 + fi + exec ${pkgs.binutils}/bin/readelf "$@" + ''; + mkExport = src: exportToolchain { @@ -196,6 +204,7 @@ let pkgs.gnutar pkgs.jq pkgs.openssl + pkgs.patchelf ]; allowedReferences = [ ]; } @@ -208,6 +217,16 @@ let else "-Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 -Wl,--disable-new-dtags" } fixture.c -o payload/bin/fixture-tool + ${ + if static then + "" + else + '' + patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 \ + --set-rpath /unused payload/bin/fixture-tool + patchelf --remove-rpath payload/bin/fixture-tool + '' + } tar --create --format=gnu --sort=name --mtime=@1 --owner=0 --group=0 --numeric-owner \ --file "$out/artifact.tar" --directory payload . digest="sha256-$(openssl dgst -sha256 -binary "$out/artifact.tar" | openssl base64 -A)" @@ -280,6 +299,7 @@ in failingVersionReadelf emptyVersionReadelf multilineInterpreterReadelf + hiddenInterpreterReadelf ; storeReferenceExport = mkExport storeReferenceSource; escapingSymlinkExport = mkExport escapingSymlinkSource; diff --git a/nix/workspace-tools/lib/tests/buck2-bridge.sh b/nix/workspace-tools/lib/tests/buck2-bridge.sh index da4a57b4a..c2d62b20e 100755 --- a/nix/workspace-tools/lib/tests/buck2-bridge.sh +++ b/nix/workspace-tools/lib/tests/buck2-bridge.sh @@ -122,14 +122,70 @@ grep -Fx 'buck2-bridge-ok' "$buck_evidence" >/dev/null || { } export BUCK2_BRIDGE_EXPORT_OUT="$export_out" + +static_import="$(build_expr "($base_expr).staticElfImport")" +[ -x "$static_import/bin/fixture-tool" ] || { + echo "buck2-bridge-test: static ELF import omitted its entrypoint" >&2 + exit 1 +} +echo "buck2-bridge-test: GREEN static ELF import" + +expect_build_failure \ + "dynamic ELF as self-contained" \ + "self-contained ELF declares an interpreter" \ + "($base_expr).dynamicElfImport" + +needed_only_expr="let + $common_let + dynamic = builtins.fromJSON (builtins.readFile \"\${test.dynamicExport}/descriptor.json\"); + descriptor = dynamic // { + platform = { os = \"linux\"; architecture = \"x86_64\"; abi = \"musl\"; }; + runtime = { kind = \"self-contained\"; inspectionContract = \"elf-static/v1\"; }; + }; + importArtifact = import (repo + \"/nix/workspace-tools/lib/buck2-artifact-import.nix\") { + inherit pkgs; + inspectElfStatic = import (repo + \"/nix/workspace-tools/lib/buck2-runtime-inspect-elf-static.nix\") { + inherit pkgs; + readelf = test.hiddenInterpreterReadelf; + }; + }; +in importArtifact { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = descriptor.platform; + artifact = test.dynamicExport + \"/artifact.tar\"; +}" +expect_build_failure \ + "self-contained ELF with DT_NEEDED" \ + "self-contained ELF declares a shared-library dependency" \ + "$needed_only_expr" + +expect_build_failure \ + "store reference in static ELF" \ + "forbidden Nix store reference" \ + "($base_expr).storeReferenceElfImport" + +expect_build_failure \ + "foreign architecture static ELF" \ + "static ELF inspector admits only linux/x86_64/musl" \ + "($base_expr).foreignArchitectureImport" + unsupported_runtime_expr="let $common_let exported = builtins.storePath (builtins.getEnv \"BUCK2_BRIDGE_EXPORT_OUT\"); original = builtins.fromJSON (builtins.readFile (exported + \"/descriptor.json\")); - descriptor = mkStrictDescriptor { + baseDescriptor = mkStrictDescriptor { inherit original; entrypoints = [ \"bin/fixture-tool\" ]; }; + descriptor = baseDescriptor // { + runtime = { + kind = \"interpreter\"; + program = \"bin/fixture-tool\"; + runtimeContract = \"fixture-shell/v1\"; + runtimeId = \"sh\"; + }; + }; in test.mkImport { inherit descriptor; expectedDescriptorDigest = contract.descriptorDigest descriptor; @@ -138,7 +194,7 @@ unsupported_runtime_expr="let }" expect_build_failure \ "unsupported build-product runtime" \ - "runtime inspector is not available for self-contained" \ + "runtime inspector is not available for interpreter" \ "$unsupported_runtime_expr" dynamic_export="$(build_expr "($base_expr).dynamicExport")" diff --git a/nix/workspace-tools/lib/tests/buck2-rust-toolchain-identity-static.sh b/nix/workspace-tools/lib/tests/buck2-rust-toolchain-identity-static.sh new file mode 100755 index 000000000..eae89d68e --- /dev/null +++ b/nix/workspace-tools/lib/tests/buck2-rust-toolchain-identity-static.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd -P)}" +nix_source="$repo_root/nix/workspace-tools/lib/buck2-rust-local-toolchain-config.nix" +buck_source="$repo_root/buck2/rust/local_store.bzl" +prelude_source="$repo_root/buck2/toolchains/nix_local.bzl" +devenv_source="$repo_root/devenv.nix" + +extract_nix_keys() { + local binding="$1" + sed -n "/ $binding = builtins.concatStringsSep/,/ ];/p" "$nix_source" \ + | sed -n 's/^[[:space:]]*"\([a-z_]*\)=.*/\1/p' +} + +extract_buck_keys() { + local function="$1" + local source="${2:-$buck_source}" + sed -n "/def $function(ctx):/,/^def /p" "$source" \ + | sed -n 's/^[[:space:]]*"\([a-z_]*\)=".*/\1/p' +} + +assert_same_keys() { + local label="$1" + local left="$2" + local right="$3" + [ "$left" = "$right" ] || { + echo "buck2-rust-toolchain-identity-static: $label key mismatch" >&2 + diff -u <(printf '%s\n' "$left") <(printf '%s\n' "$right") >&2 || true + exit 1 + } +} + +config_keys="$(extract_nix_keys configIntegrityMaterial)" +compile_keys="$(extract_nix_keys compileMaterial)" +assert_same_keys config-integrity "$config_keys" "$(extract_buck_keys _config_integrity_material)" +assert_same_keys compile "$compile_keys" "$(extract_buck_keys _compile_identity_material)" +assert_same_keys conventional-compile "$compile_keys" "$(extract_buck_keys _compile_identity_material "$prelude_source")" + +grep -F 'compiler = RunInfo(args = [' "$prelude_source" >/dev/null +grep -F 'ctx.attrs.identity_verifier' "$prelude_source" >/dev/null +grep -F 'ctx.attrs.compile_identity_material' "$prelude_source" >/dev/null +grep -F 'ctx.attrs.compile_identity' "$prelude_source" >/dev/null +grep -F 'ctx.attrs.rustc' "$prelude_source" >/dev/null +grep -F '//packages/@overeng/otel-scrape:product' "$devenv_source" >/dev/null +grep -F -- '--config rust_toolchain.compile_identity=sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' "$devenv_source" >/dev/null +grep -F 'false OTEL compile identity unexpectedly admitted' "$devenv_source" >/dev/null + +expected_compile_keys='ar +cc +contract +cxx +execution_platform +linker +rustc +target_platform +target_triple +tool_path' +assert_same_keys compile-contract "$compile_keys" "$expected_compile_keys" + +for irrelevant in clippy_driver dwp nm objcopy objdump python ranlib rustdoc strip; do + grep -Fx "$irrelevant" <<<"$config_keys" >/dev/null + if grep -Fx "$irrelevant" <<<"$compile_keys" >/dev/null; then + echo "buck2-rust-toolchain-identity-static: irrelevant compile key admitted: $irrelevant" >&2 + exit 1 + fi +done + +material_digest() { + local ar="$1" + local rustdoc="$2" + local compile="ar=$ar;cc=/store/cc;contract=v1;cxx=/store/cxx;execution_platform=exec;linker=/store/ld;rustc=/store/rustc;target_platform=target;target_triple=triple;tool_path=/store/core/bin" + local config="ar=$ar;cc=/store/cc;clippy_driver=/store/clippy;contract=v1;cxx=/store/cxx;dwp=/store/dwp;execution_platform=exec;identity_verifier=/store/verify;linker=/store/ld;nm=/store/nm;objcopy=/store/objcopy;objdump=/store/objdump;python=/store/python;ranlib=/store/ranlib;rustc=/store/rustc;rustdoc=$rustdoc;strip=/store/strip;target_platform=target;target_triple=triple;tool_path=/store/core/bin" + printf '%s %s\n' "$(printf '%s' "$config" | sha256sum | awk '{print $1}')" "$(printf '%s' "$compile" | sha256sum | awk '{print $1}')" +} + +read -r base_config base_compile < <(material_digest /store/ar /store/rustdoc) +read -r docs_config docs_compile < <(material_digest /store/ar /store/rustdoc-v2) +read -r ar_config ar_compile < <(material_digest /store/ar-v2 /store/rustdoc) + +[ "$base_config" != "$docs_config" ] +[ "$base_compile" = "$docs_compile" ] +[ "$base_config" != "$ar_config" ] +[ "$base_compile" != "$ar_compile" ] + +echo "buck2-rust-toolchain-identity-static: PASS irrelevant_rustdoc=stable relevant_ar=invalidates" diff --git a/packages/@overeng/BUCK b/packages/@overeng/BUCK new file mode 100644 index 000000000..cf245a324 --- /dev/null +++ b/packages/@overeng/BUCK @@ -0,0 +1,309 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +filegroup( + name = "content-address_production_sources", + srcs = glob([ + "content-address/package.json", + "content-address/tsconfig.json", + "content-address/src/**/*.cts", + "content-address/src/**/*.mts", + "content-address/src/**/*.ts", + "content-address/src/**/*.tsx", + ], exclude = [ + "content-address/src/**/*.test.ts", + "content-address/src/**/*.test.tsx", + "content-address/src/**/*.stories.ts", + "content-address/src/**/*.stories.tsx", + "content-address/src/**/stories/**", + "content-address/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "content-address_project_sources", + srcs = glob([ + "content-address/package.json", + "content-address/tsconfig.json", + "content-address/src/**/*.cts", + "content-address/src/**/*.mts", + "content-address/src/**/*.ts", + "content-address/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "effect-distributed-lock_production_sources", + srcs = glob([ + "effect-distributed-lock/package.json", + "effect-distributed-lock/tsconfig.json", + "effect-distributed-lock/src/**/*.cts", + "effect-distributed-lock/src/**/*.mts", + "effect-distributed-lock/src/**/*.ts", + "effect-distributed-lock/src/**/*.tsx", + ], exclude = [ + "effect-distributed-lock/src/**/*.test.ts", + "effect-distributed-lock/src/**/*.test.tsx", + "effect-distributed-lock/src/**/*.stories.ts", + "effect-distributed-lock/src/**/*.stories.tsx", + "effect-distributed-lock/src/**/stories/**", + "effect-distributed-lock/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "effect-distributed-lock_project_sources", + srcs = glob([ + "effect-distributed-lock/package.json", + "effect-distributed-lock/tsconfig.json", + "effect-distributed-lock/src/**/*.cts", + "effect-distributed-lock/src/**/*.mts", + "effect-distributed-lock/src/**/*.ts", + "effect-distributed-lock/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "effect-path_production_sources", + srcs = glob([ + "effect-path/package.json", + "effect-path/tsconfig.json", + "effect-path/src/**/*.cts", + "effect-path/src/**/*.mts", + "effect-path/src/**/*.ts", + "effect-path/src/**/*.tsx", + ], exclude = [ + "effect-path/src/**/*.test.ts", + "effect-path/src/**/*.test.tsx", + "effect-path/src/**/*.stories.ts", + "effect-path/src/**/*.stories.tsx", + "effect-path/src/**/stories/**", + "effect-path/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "effect-path_project_sources", + srcs = glob([ + "effect-path/package.json", + "effect-path/tsconfig.json", + "effect-path/src/**/*.cts", + "effect-path/src/**/*.mts", + "effect-path/src/**/*.ts", + "effect-path/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "kdl-effect_production_sources", + srcs = glob([ + "kdl-effect/package.json", + "kdl-effect/tsconfig.json", + "kdl-effect/src/**/*.cts", + "kdl-effect/src/**/*.mts", + "kdl-effect/src/**/*.ts", + "kdl-effect/src/**/*.tsx", + ], exclude = [ + "kdl-effect/src/**/*.test.ts", + "kdl-effect/src/**/*.test.tsx", + "kdl-effect/src/**/*.stories.ts", + "kdl-effect/src/**/*.stories.tsx", + "kdl-effect/src/**/stories/**", + "kdl-effect/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "kdl-effect_project_sources", + srcs = glob([ + "kdl-effect/package.json", + "kdl-effect/tsconfig.json", + "kdl-effect/src/**/*.cts", + "kdl-effect/src/**/*.mts", + "kdl-effect/src/**/*.ts", + "kdl-effect/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "kdl_production_sources", + srcs = glob([ + "kdl/package.json", + "kdl/tsconfig.json", + "kdl/src/**/*.cts", + "kdl/src/**/*.mts", + "kdl/src/**/*.ts", + "kdl/src/**/*.tsx", + ], exclude = [ + "kdl/src/**/*.test.ts", + "kdl/src/**/*.test.tsx", + "kdl/src/**/*.stories.ts", + "kdl/src/**/*.stories.tsx", + "kdl/src/**/stories/**", + "kdl/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "kdl_project_sources", + srcs = glob([ + "kdl/package.json", + "kdl/tsconfig.json", + "kdl/src/**/*.cts", + "kdl/src/**/*.mts", + "kdl/src/**/*.ts", + "kdl/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "otel-contract_production_sources", + srcs = glob([ + "otel-contract/package.json", + "otel-contract/tsconfig.json", + "otel-contract/src/**/*.cts", + "otel-contract/src/**/*.mts", + "otel-contract/src/**/*.ts", + "otel-contract/src/**/*.tsx", + ], exclude = [ + "otel-contract/src/**/*.test.ts", + "otel-contract/src/**/*.test.tsx", + "otel-contract/src/**/*.stories.ts", + "otel-contract/src/**/*.stories.tsx", + "otel-contract/src/**/stories/**", + "otel-contract/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "otel-contract_project_sources", + srcs = glob([ + "otel-contract/package.json", + "otel-contract/tsconfig.json", + "otel-contract/src/**/*.cts", + "otel-contract/src/**/*.mts", + "otel-contract/src/**/*.ts", + "otel-contract/src/**/*.tsx", + ], exclude = [ + "otel-contract/src/**/*.genie.ts", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "tui-react_production_sources", + srcs = glob([ + "tui-react/package.json", + "tui-react/tsconfig.json", + "tui-react/src/**/*.cts", + "tui-react/src/**/*.mts", + "tui-react/src/**/*.ts", + "tui-react/src/**/*.tsx", + ], exclude = [ + "tui-react/src/**/*.test.ts", + "tui-react/src/**/*.test.tsx", + "tui-react/src/**/*.stories.ts", + "tui-react/src/**/*.stories.tsx", + "tui-react/src/**/stories/**", + "tui-react/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "tui-react_project_sources", + srcs = glob([ + "tui-react/package.json", + "tui-react/tsconfig.json", + "tui-react/src/**/*.cts", + "tui-react/src/**/*.mts", + "tui-react/src/**/*.ts", + "tui-react/src/**/*.tsx", + "tui-react/test/**/*.cts", + "tui-react/test/**/*.mts", + "tui-react/test/**/*.ts", + "tui-react/test/**/*.tsx", + "tui-react/examples/**/*.cts", + "tui-react/examples/**/*.mts", + "tui-react/examples/**/*.ts", + "tui-react/examples/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "utils-dev_production_sources", + srcs = glob([ + "utils-dev/package.json", + "utils-dev/tsconfig.json", + "utils-dev/src/**/*.cts", + "utils-dev/src/**/*.mts", + "utils-dev/src/**/*.ts", + "utils-dev/src/**/*.tsx", + ], exclude = [ + "utils-dev/src/**/*.test.ts", + "utils-dev/src/**/*.test.tsx", + "utils-dev/src/**/*.stories.ts", + "utils-dev/src/**/*.stories.tsx", + "utils-dev/src/**/stories/**", + "utils-dev/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "utils-dev_project_sources", + srcs = glob([ + "utils-dev/package.json", + "utils-dev/tsconfig.json", + "utils-dev/src/**/*.cts", + "utils-dev/src/**/*.mts", + "utils-dev/src/**/*.ts", + "utils-dev/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "utils_production_sources", + srcs = glob([ + "utils/package.json", + "utils/tsconfig.json", + "utils/src/**/*.cts", + "utils/src/**/*.mts", + "utils/src/**/*.ts", + "utils/src/**/*.tsx", + ], exclude = [ + "utils/src/**/*.test.ts", + "utils/src/**/*.test.tsx", + "utils/src/**/*.stories.ts", + "utils/src/**/*.stories.tsx", + "utils/src/**/stories/**", + "utils/src/test-utils/**", + ]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "utils_project_sources", + srcs = glob([ + "utils/package.json", + "utils/tsconfig.json", + "utils/src/**/*.cts", + "utils/src/**/*.mts", + "utils/src/**/*.ts", + "utils/src/**/*.tsx", + ]), + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/BUCK.genie.ts b/packages/@overeng/BUCK.genie.ts new file mode 100644 index 000000000..7237525be --- /dev/null +++ b/packages/@overeng/BUCK.genie.ts @@ -0,0 +1,80 @@ +import { createGenieOutput } from './genie/src/runtime/core.ts' +import { workspacePackages } from './megarepo/buck2/workspace-packages.ts' + +const sourceExtensions = ['cts', 'mts', 'ts', 'tsx'] as const +const productionPatterns = [ + 'package.json', + 'tsconfig.json', + 'src/**/*.cts', + 'src/**/*.mts', + 'src/**/*.ts', + 'src/**/*.tsx', +] as const +type TsconfigOutput = { + readonly data: { + readonly include?: readonly string[] + readonly exclude?: readonly string[] + } +} +const expandTypeScriptPattern = (pattern: string): readonly string[] => { + if (sourceExtensions.some((extension) => pattern.endsWith(`.${extension}`)) === true) + return [pattern] + if (pattern.endsWith('*') === true) + return sourceExtensions.map((extension) => `${pattern}.${extension}`) + throw new Error(`Unsupported tsconfig source pattern for Buck projection: ${pattern}`) +} +const projectPatterns = (tsconfig: TsconfigOutput): readonly string[] => [ + 'package.json', + 'tsconfig.json', + ...(tsconfig.data.include ?? []).flatMap(expandTypeScriptPattern), +] +const projectExcludes = (tsconfig: TsconfigOutput): readonly string[] => + (tsconfig.data.exclude ?? []).flatMap(expandTypeScriptPattern) +const productionExcludes = [ + 'src/**/*.test.ts', + 'src/**/*.test.tsx', + 'src/**/*.stories.ts', + 'src/**/*.stories.tsx', + 'src/**/stories/**', + 'src/test-utils/**', +] as const +const renderTarget = ({ + name, + role, + patterns, + exclude, +}: { + name: string + role: string + patterns: readonly string[] + exclude: readonly string[] +}): string => `filegroup( + name = ${JSON.stringify(`${name}_${role}_sources`)}, + srcs = glob([${patterns.map((path) => `\n ${JSON.stringify(`${name}/${path}`)},`).join('')}\n ]${exclude.length === 0 ? '' : `, exclude = [${exclude.map((path) => `\n ${JSON.stringify(`${name}/${path}`)},`).join('')}\n ]`}), + visibility = ["PUBLIC"], +)` +const rendered = Object.entries(workspacePackages) + .filter(([name]) => name !== '@overeng/tui-core') + .flatMap(([fullName, { tsconfig }]) => { + const name = fullName.slice('@overeng/'.length) + return [ + renderTarget({ + name, + role: 'production', + patterns: productionPatterns, + exclude: productionExcludes, + }), + renderTarget({ + name, + role: 'project', + patterns: projectPatterns(tsconfig), + exclude: projectExcludes(tsconfig), + }), + ] + }) + .join('\n\n') + +export default createGenieOutput({ + data: { packageNames: Object.keys(workspacePackages) }, + stringify: () => `${rendered}\n`, +}) diff --git a/packages/@overeng/buck2-tools/src/stage0-config.integration.test.ts b/packages/@overeng/buck2-tools/src/stage0-config.integration.test.ts index b6935b6ca..aaad7251f 100644 --- a/packages/@overeng/buck2-tools/src/stage0-config.integration.test.ts +++ b/packages/@overeng/buck2-tools/src/stage0-config.integration.test.ts @@ -140,6 +140,7 @@ attribute="\${installable##*#}" case "$attribute" in buck2-closure-tool) executable="buck2-closure-tool" ;; buck2-package-evidence) executable="buck2-package-evidence" ;; + buck2-typescript-product) executable="buck2-typescript-product" ;; buck2-portable-toolchain) executable="buck2-portable-toolchain" ;; buck2-portable-toolchain-fixture) executable="buck2-portable-toolchain-fixture" ;; *) echo "unexpected attribute: $attribute" >&2; exit 64 ;; @@ -189,18 +190,18 @@ printf '%s\\n' "$output" it('hits across unrelated mutations and misses across semantic mutations', async () => { const cold = await runCli({ root, cacheRoot }) expect(cold).toMatchObject({ exitCode: 0, stderr: '' }) - expect(await invocationCount(root)).toBe(4) + expect(await invocationCount(root)).toBe(5) await writeFile(join(root, 'unrelated.txt'), 'unrelated two\n') const unrelated = await runCli({ root, cacheRoot }) expect(unrelated).toMatchObject({ exitCode: 0, stdout: cold.stdout, stderr: '' }) - expect(await invocationCount(root)).toBe(4) + expect(await invocationCount(root)).toBe(5) await writeFile(join(root, 'semantic.txt'), 'version two\n') const semantic = await runCli({ root, cacheRoot }) expect(semantic.exitCode).toBe(0) expect(semantic.stdout).not.toBe(cold.stdout) - expect(await invocationCount(root)).toBe(8) + expect(await invocationCount(root)).toBe(10) }) it('copies only fingerprinted inputs into the immutable source snapshot', async () => { @@ -258,7 +259,7 @@ printf '%s\\n' "$output" const repaired = await runCli({ root, cacheRoot }) expect(repaired).toMatchObject({ exitCode: 0, stdout: cold.stdout, stderr: '' }) - expect(await invocationCount(root)).toBe(8) + expect(await invocationCount(root)).toBe(10) expect((await stat(config.closure_tool!)).mode & 0o111).not.toBe(0) expect((await stat(configPath)).mode & 0o222).toBe(0) }) @@ -279,18 +280,18 @@ printf '%s\\n' "$output" ) const fingerprintRepaired = await runCli({ root, cacheRoot }) expect(fingerprintRepaired.exitCode).toBe(0) - expect(await invocationCount(root)).toBe(8) + expect(await invocationCount(root)).toBe(10) await chmod(configPath, 0o600) await writeFile(configPath, original.replace(/^# Resolver ABI: .+$/mu, '# Resolver ABI: stale')) const abiRepaired = await runCli({ root, cacheRoot }) expect(abiRepaired.exitCode).toBe(0) - expect(await invocationCount(root)).toBe(12) + expect(await invocationCount(root)).toBe(15) await unlink(join(dirname(configPath), 'roots', 'closure_tool')) const rootRepaired = await runCli({ root, cacheRoot }) expect(rootRepaired.exitCode).toBe(0) - expect(await invocationCount(root)).toBe(16) + expect(await invocationCount(root)).toBe(20) }) it('single-flights concurrent cold callers under flock', async () => { @@ -300,7 +301,7 @@ printf '%s\\n' "$output" ) expect(results.every(({ exitCode, stderr }) => exitCode === 0 && stderr === '')).toBe(true) expect(new Set(results.map(({ stdout }) => stdout).filter(Boolean)).size).toBe(1) - expect(await invocationCount(root)).toBe(4) + expect(await invocationCount(root)).toBe(5) const configPath = results[0]!.stdout.trim() expect(dirname(configPath)).toMatch(concurrentCache) expect(await readFile(configPath, 'utf8')).toContain('[buck2_stage0]') @@ -310,7 +311,7 @@ printf '%s\\n' "$output" const result = await runCli({ root, cacheRoot, mutateDuringRealization: true }) expect(result).toMatchObject({ exitCode: 0, stderr: '' }) expect(await readFile(join(root, 'semantic.txt'), 'utf8')).toBe('version two\n') - expect(await invocationCount(root)).toBe(8) + expect(await invocationCount(root)).toBe(10) const configPath = result.stdout.trim() const entries = await readdir(cacheRoot) const lockFingerprints = entries @@ -324,7 +325,7 @@ printf '%s\\n' "$output" const result = await runCli({ root, cacheRoot, mutateDuringEveryRealization: true }) expect(result.exitCode).toBe(1) expect(result.stderr).toContain('semantic inputs remained unstable after 3 attempts') - expect(await invocationCount(root)).toBe(12) + expect(await invocationCount(root)).toBe(15) }) it('rejects a semantic input symlink which escapes the repository', async () => { diff --git a/packages/@overeng/buck2-tools/src/stage0-config.ts b/packages/@overeng/buck2-tools/src/stage0-config.ts index ab5e82faa..2b6e20145 100644 --- a/packages/@overeng/buck2-tools/src/stage0-config.ts +++ b/packages/@overeng/buck2-tools/src/stage0-config.ts @@ -31,6 +31,11 @@ export const stage0Tools = [ flakeAttribute: 'buck2-package-evidence', executable: 'bin/buck2-package-evidence', }, + { + configKey: 'typescript_product_tool', + flakeAttribute: 'buck2-typescript-product', + executable: 'bin/buck2-typescript-product', + }, { configKey: 'portable_toolchain', flakeAttribute: 'buck2-portable-toolchain', diff --git a/packages/@overeng/megarepo/BUCK b/packages/@overeng/megarepo/BUCK new file mode 100644 index 000000000..a697a4a8d --- /dev/null +++ b/packages/@overeng/megarepo/BUCK @@ -0,0 +1,808 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Role closures derive from package.json.genie.ts and tsconfig.json.genie.ts. +load("//buck2:typescript.bzl", "typescript_cli", "typescript_project_check") + +filegroup( + name = "production_sources", + srcs = [ + "bin/mr.ts", + "package.json", + "src/buck2-declared-unreachable-fixture.ts", + "src/cli/commands/add.ts", + "src/cli/commands/apply.ts", + "src/cli/commands/check.ts", + "src/cli/commands/config/mod.ts", + "src/cli/commands/config/push-refs.ts", + "src/cli/commands/deps.ts", + "src/cli/commands/engine.ts", + "src/cli/commands/env.ts", + "src/cli/commands/exec.ts", + "src/cli/commands/fetch.ts", + "src/cli/commands/generate/mod.ts", + "src/cli/commands/init.ts", + "src/cli/commands/lock.ts", + "src/cli/commands/ls.ts", + "src/cli/commands/mod.ts", + "src/cli/commands/pin.ts", + "src/cli/commands/root.ts", + "src/cli/commands/status.ts", + "src/cli/commands/store/mod.ts", + "src/cli/components/Header.tsx", + "src/cli/components/LogLine.tsx", + "src/cli/components/MemberRow.tsx", + "src/cli/components/Scope.tsx", + "src/cli/components/Separator.tsx", + "src/cli/components/StatusIcon.tsx", + "src/cli/components/Summary.tsx", + "src/cli/components/TaskItem.tsx", + "src/cli/components/mod.ts", + "src/cli/components/tokens.ts", + "src/cli/context.ts", + "src/cli/errors.ts", + "src/cli/mod.ts", + "src/cli/observability.ts", + "src/cli/renderers/AddOutput/app.ts", + "src/cli/renderers/AddOutput/mod.ts", + "src/cli/renderers/AddOutput/schema.ts", + "src/cli/renderers/AddOutput/view.tsx", + "src/cli/renderers/DepsOutput/app.ts", + "src/cli/renderers/DepsOutput/mod.ts", + "src/cli/renderers/DepsOutput/schema.ts", + "src/cli/renderers/DepsOutput/view.tsx", + "src/cli/renderers/EnvOutput/app.ts", + "src/cli/renderers/EnvOutput/mod.ts", + "src/cli/renderers/EnvOutput/schema.ts", + "src/cli/renderers/EnvOutput/view.tsx", + "src/cli/renderers/ExecOutput/app.ts", + "src/cli/renderers/ExecOutput/mod.ts", + "src/cli/renderers/ExecOutput/schema.ts", + "src/cli/renderers/ExecOutput/view.tsx", + "src/cli/renderers/GenerateOutput/app.ts", + "src/cli/renderers/GenerateOutput/mod.ts", + "src/cli/renderers/GenerateOutput/schema.ts", + "src/cli/renderers/GenerateOutput/view.tsx", + "src/cli/renderers/InitOutput/app.ts", + "src/cli/renderers/InitOutput/mod.ts", + "src/cli/renderers/InitOutput/schema.ts", + "src/cli/renderers/InitOutput/view.tsx", + "src/cli/renderers/LsOutput/app.ts", + "src/cli/renderers/LsOutput/mod.ts", + "src/cli/renderers/LsOutput/schema.ts", + "src/cli/renderers/LsOutput/view.tsx", + "src/cli/renderers/PinOutput/app.ts", + "src/cli/renderers/PinOutput/mod.ts", + "src/cli/renderers/PinOutput/schema.ts", + "src/cli/renderers/PinOutput/view.tsx", + "src/cli/renderers/PushRefsOutput/app.ts", + "src/cli/renderers/PushRefsOutput/mod.ts", + "src/cli/renderers/PushRefsOutput/schema.ts", + "src/cli/renderers/PushRefsOutput/view.tsx", + "src/cli/renderers/RootOutput/app.ts", + "src/cli/renderers/RootOutput/mod.ts", + "src/cli/renderers/RootOutput/schema.ts", + "src/cli/renderers/RootOutput/view.tsx", + "src/cli/renderers/StatusOutput/app.ts", + "src/cli/renderers/StatusOutput/mod.ts", + "src/cli/renderers/StatusOutput/schema.ts", + "src/cli/renderers/StatusOutput/view.tsx", + "src/cli/renderers/StoreOutput/app.ts", + "src/cli/renderers/StoreOutput/mod.ts", + "src/cli/renderers/StoreOutput/schema.ts", + "src/cli/renderers/StoreOutput/view.tsx", + "src/cli/renderers/SyncOutput/app.ts", + "src/cli/renderers/SyncOutput/mod.ts", + "src/cli/renderers/SyncOutput/schema.ts", + "src/cli/renderers/SyncOutput/ui.ts", + "src/cli/renderers/SyncOutput/view.tsx", + "src/cli/renderers/_story-constants.ts", + "src/cli/renderers/mod.ts", + "src/git.contract.ts", + "src/lib/config.ts", + "src/lib/generators/mod.ts", + "src/lib/generators/schema.ts", + "src/lib/generators/vscode.ts", + "src/lib/git.ts", + "src/lib/issues.ts", + "src/lib/lock.ts", + "src/lib/megarepo-traversal.ts", + "src/lib/nix-lock/flake-url.ts", + "src/lib/nix-lock/input-discovery.ts", + "src/lib/nix-lock/matcher.ts", + "src/lib/nix-lock/mod.ts", + "src/lib/nix-lock/schema.ts", + "src/lib/nix-lock/source-rewriter.ts", + "src/lib/observability.ts", + "src/lib/ref.ts", + "src/lib/source-policy.ts", + "src/lib/store-archive.ts", + "src/lib/store-fs-atomic.ts", + "src/lib/store-gc-config.ts", + "src/lib/store-gc-observations.ts", + "src/lib/store-hygiene.ts", + "src/lib/store-liveness.ts", + "src/lib/store-lock.ts", + "src/lib/store-lossless.ts", + "src/lib/store-path.ts", + "src/lib/store-pr-state.ts", + "src/lib/store-worktree-policy.ts", + "src/lib/store.ts", + "src/lib/sync/member.ts", + "src/lib/sync/mod.ts", + "src/lib/sync/schema.ts", + "src/lib/sync/types.ts", + "src/lib/version.ts", + "src/megarepo.contract.ts", + "src/mod.ts", + "src/nix.contract.ts", + ], + visibility = ["PUBLIC"], +) + +filegroup( + name = "project_sources", + srcs = [ + "bin/mr.ts", + "package.json", + "src/buck2-declared-unreachable-fixture.ts", + "src/cli.contract.test.ts", + "src/cli/cli.integration.test.ts", + "src/cli/commands/add.ts", + "src/cli/commands/apply.ts", + "src/cli/commands/check.ts", + "src/cli/commands/config/mod.ts", + "src/cli/commands/config/push-refs.ts", + "src/cli/commands/deps.ts", + "src/cli/commands/engine.ts", + "src/cli/commands/env.ts", + "src/cli/commands/exec.ts", + "src/cli/commands/fetch.ts", + "src/cli/commands/generate/mod.ts", + "src/cli/commands/init.ts", + "src/cli/commands/lock.ts", + "src/cli/commands/ls.ts", + "src/cli/commands/mod.ts", + "src/cli/commands/pin.ts", + "src/cli/commands/root.ts", + "src/cli/commands/status.ts", + "src/cli/commands/store/mod.ts", + "src/cli/components/Header.stories.tsx", + "src/cli/components/Header.tsx", + "src/cli/components/LogLine.stories.tsx", + "src/cli/components/LogLine.tsx", + "src/cli/components/MemberRow.tsx", + "src/cli/components/Scope.tsx", + "src/cli/components/Separator.stories.tsx", + "src/cli/components/Separator.tsx", + "src/cli/components/StatusIcon.stories.tsx", + "src/cli/components/StatusIcon.tsx", + "src/cli/components/Summary.stories.tsx", + "src/cli/components/Summary.tsx", + "src/cli/components/TaskItem.stories.tsx", + "src/cli/components/TaskItem.tsx", + "src/cli/components/mod.ts", + "src/cli/components/tokens.ts", + "src/cli/context.ts", + "src/cli/errors.ts", + "src/cli/mod.ts", + "src/cli/observability.ts", + "src/cli/pin.integration.test.ts", + "src/cli/prompt-select-pty-fixture.ts", + "src/cli/prompt-select-pty.test.ts", + "src/cli/renderers/AddOutput/app.ts", + "src/cli/renderers/AddOutput/mod.ts", + "src/cli/renderers/AddOutput/schema.ts", + "src/cli/renderers/AddOutput/stories/Errors.stories.tsx", + "src/cli/renderers/AddOutput/stories/Success.stories.tsx", + "src/cli/renderers/AddOutput/stories/_fixtures.ts", + "src/cli/renderers/AddOutput/view.tsx", + "src/cli/renderers/DepsOutput/app.ts", + "src/cli/renderers/DepsOutput/mod.ts", + "src/cli/renderers/DepsOutput/schema.ts", + "src/cli/renderers/DepsOutput/stories/Basic.stories.tsx", + "src/cli/renderers/DepsOutput/stories/_fixtures.ts", + "src/cli/renderers/DepsOutput/view.tsx", + "src/cli/renderers/EnvOutput/app.ts", + "src/cli/renderers/EnvOutput/mod.ts", + "src/cli/renderers/EnvOutput/schema.ts", + "src/cli/renderers/EnvOutput/view.tsx", + "src/cli/renderers/ExecOutput/app.ts", + "src/cli/renderers/ExecOutput/mod.ts", + "src/cli/renderers/ExecOutput/schema.ts", + "src/cli/renderers/ExecOutput/stories/Complete.stories.tsx", + "src/cli/renderers/ExecOutput/stories/Errors.stories.tsx", + "src/cli/renderers/ExecOutput/stories/Running.stories.tsx", + "src/cli/renderers/ExecOutput/stories/_fixtures.ts", + "src/cli/renderers/ExecOutput/view.tsx", + "src/cli/renderers/GenerateOutput/app.ts", + "src/cli/renderers/GenerateOutput/mod.ts", + "src/cli/renderers/GenerateOutput/schema.ts", + "src/cli/renderers/GenerateOutput/view.tsx", + "src/cli/renderers/InitOutput/app.ts", + "src/cli/renderers/InitOutput/mod.ts", + "src/cli/renderers/InitOutput/schema.ts", + "src/cli/renderers/InitOutput/view.tsx", + "src/cli/renderers/LsOutput/app.ts", + "src/cli/renderers/LsOutput/mod.ts", + "src/cli/renderers/LsOutput/schema.ts", + "src/cli/renderers/LsOutput/stories/Basic.stories.tsx", + "src/cli/renderers/LsOutput/stories/Nested.stories.tsx", + "src/cli/renderers/LsOutput/stories/Sources.stories.tsx", + "src/cli/renderers/LsOutput/stories/_fixtures.ts", + "src/cli/renderers/LsOutput/view.tsx", + "src/cli/renderers/PinOutput/app.ts", + "src/cli/renderers/PinOutput/mod.ts", + "src/cli/renderers/PinOutput/schema.ts", + "src/cli/renderers/PinOutput/stories/Errors.stories.tsx", + "src/cli/renderers/PinOutput/stories/Success.stories.tsx", + "src/cli/renderers/PinOutput/stories/Warnings.stories.tsx", + "src/cli/renderers/PinOutput/stories/_fixtures.ts", + "src/cli/renderers/PinOutput/view.tsx", + "src/cli/renderers/PushRefsOutput/app.ts", + "src/cli/renderers/PushRefsOutput/mod.ts", + "src/cli/renderers/PushRefsOutput/schema.ts", + "src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx", + "src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx", + "src/cli/renderers/PushRefsOutput/stories/_fixtures.ts", + "src/cli/renderers/PushRefsOutput/view.tsx", + "src/cli/renderers/RootOutput/app.ts", + "src/cli/renderers/RootOutput/mod.ts", + "src/cli/renderers/RootOutput/schema.ts", + "src/cli/renderers/RootOutput/stories/Errors.stories.tsx", + "src/cli/renderers/RootOutput/stories/Success.stories.tsx", + "src/cli/renderers/RootOutput/stories/_fixtures.ts", + "src/cli/renderers/RootOutput/view.tsx", + "src/cli/renderers/StatusOutput/app.ts", + "src/cli/renderers/StatusOutput/mod.ts", + "src/cli/renderers/StatusOutput/schema.ts", + "src/cli/renderers/StatusOutput/stories/Basic.stories.tsx", + "src/cli/renderers/StatusOutput/stories/Complex.stories.tsx", + "src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/_fixtures.ts", + "src/cli/renderers/StatusOutput/view.tsx", + "src/cli/renderers/StoreOutput/app.ts", + "src/cli/renderers/StoreOutput/mod.ts", + "src/cli/renderers/StoreOutput/schema.ts", + "src/cli/renderers/StoreOutput/stories/Add.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Fix.stories.tsx", + "src/cli/renderers/StoreOutput/stories/GC.stories.tsx", + "src/cli/renderers/StoreOutput/stories/List.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Status.stories.tsx", + "src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx", + "src/cli/renderers/StoreOutput/stories/_fixtures.ts", + "src/cli/renderers/StoreOutput/view.tsx", + "src/cli/renderers/SyncOutput/app.ts", + "src/cli/renderers/SyncOutput/mod.ts", + "src/cli/renderers/SyncOutput/schema.ts", + "src/cli/renderers/SyncOutput/stories/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx", + "src/cli/renderers/SyncOutput/ui.ts", + "src/cli/renderers/SyncOutput/view.tsx", + "src/cli/renderers/_story-constants.ts", + "src/cli/renderers/mod.ts", + "src/cli/status.integration.test.ts", + "src/cli/store-gc-cold.integration.test.ts", + "src/cli/store-gc-otel.integration.test.ts", + "src/cli/store.integration.test.ts", + "src/cli/sync.integration.test.ts", + "src/git.contract.ts", + "src/lib/config.ts", + "src/lib/config.unit.test.ts", + "src/lib/generators/generators.unit.test.ts", + "src/lib/generators/mod.ts", + "src/lib/generators/schema.ts", + "src/lib/generators/vscode.ts", + "src/lib/git-memory.integration.test.ts", + "src/lib/git-streaming-parsers.integration.test.ts", + "src/lib/git-timeout.integration.test.ts", + "src/lib/git.ts", + "src/lib/git.unit.test.ts", + "src/lib/issues.ts", + "src/lib/json-wire-baseline.test.ts", + "src/lib/lock.ts", + "src/lib/lock.unit.test.ts", + "src/lib/megarepo-traversal.ts", + "src/lib/megarepo-traversal.unit.test.ts", + "src/lib/nix-lock/flake-url.ts", + "src/lib/nix-lock/flake-url.unit.test.ts", + "src/lib/nix-lock/input-discovery.ts", + "src/lib/nix-lock/input-discovery.unit.test.ts", + "src/lib/nix-lock/matcher.ts", + "src/lib/nix-lock/mod.ts", + "src/lib/nix-lock/mod.unit.test.ts", + "src/lib/nix-lock/schema.ts", + "src/lib/nix-lock/schema.unit.test.ts", + "src/lib/nix-lock/source-rewriter.ts", + "src/lib/nix-lock/source-rewriter.unit.test.ts", + "src/lib/observability.ts", + "src/lib/ref.ts", + "src/lib/ref.unit.test.ts", + "src/lib/source-policy.ts", + "src/lib/source-policy.unit.test.ts", + "src/lib/store-archive.integration.test.ts", + "src/lib/store-archive.ts", + "src/lib/store-fs-atomic.ts", + "src/lib/store-fs-atomic.unit.test.ts", + "src/lib/store-gc-config.ts", + "src/lib/store-gc-config.unit.test.ts", + "src/lib/store-gc-observations.ts", + "src/lib/store-gc-observations.unit.test.ts", + "src/lib/store-hygiene.ts", + "src/lib/store-hygiene.unit.test.ts", + "src/lib/store-liveness.integration.test.ts", + "src/lib/store-liveness.ts", + "src/lib/store-lock.ts", + "src/lib/store-lock.unit.test.ts", + "src/lib/store-lossless.integration.test.ts", + "src/lib/store-lossless.ts", + "src/lib/store-path.ts", + "src/lib/store-path.unit.test.ts", + "src/lib/store-pr-state.ts", + "src/lib/store-pr-state.unit.test.ts", + "src/lib/store-worktree-policy.ts", + "src/lib/store-worktree-policy.unit.test.ts", + "src/lib/store.ts", + "src/lib/sync/member.ts", + "src/lib/sync/member.unit.test.ts", + "src/lib/sync/mod.ts", + "src/lib/sync/schema.ts", + "src/lib/sync/types.ts", + "src/lib/version.ts", + "src/megarepo.contract.ts", + "src/mod.ts", + "src/nix.contract.ts", + "src/test-utils/consoleCapture.ts", + "src/test-utils/git-env-setup.ts", + "src/test-utils/json.ts", + "src/test-utils/memory-probe.ts", + "src/test-utils/mod.ts", + "src/test-utils/setup.ts", + "src/test-utils/store-setup.integration.test.ts", + "src/test-utils/store-setup.ts", + "tsconfig.json", + ], + visibility = ["PUBLIC"], +) + +typescript_project_check( + name = "typecheck", + package_path = "packages/@overeng/megarepo", + platform = "x86_64-linux", + tsconfig = "packages/@overeng/megarepo/tsconfig.json", + srcs = [ + "bin/mr.ts", + "package.json", + "src/buck2-declared-unreachable-fixture.ts", + "src/cli.contract.test.ts", + "src/cli/cli.integration.test.ts", + "src/cli/commands/add.ts", + "src/cli/commands/apply.ts", + "src/cli/commands/check.ts", + "src/cli/commands/config/mod.ts", + "src/cli/commands/config/push-refs.ts", + "src/cli/commands/deps.ts", + "src/cli/commands/engine.ts", + "src/cli/commands/env.ts", + "src/cli/commands/exec.ts", + "src/cli/commands/fetch.ts", + "src/cli/commands/generate/mod.ts", + "src/cli/commands/init.ts", + "src/cli/commands/lock.ts", + "src/cli/commands/ls.ts", + "src/cli/commands/mod.ts", + "src/cli/commands/pin.ts", + "src/cli/commands/root.ts", + "src/cli/commands/status.ts", + "src/cli/commands/store/mod.ts", + "src/cli/components/Header.stories.tsx", + "src/cli/components/Header.tsx", + "src/cli/components/LogLine.stories.tsx", + "src/cli/components/LogLine.tsx", + "src/cli/components/MemberRow.tsx", + "src/cli/components/Scope.tsx", + "src/cli/components/Separator.stories.tsx", + "src/cli/components/Separator.tsx", + "src/cli/components/StatusIcon.stories.tsx", + "src/cli/components/StatusIcon.tsx", + "src/cli/components/Summary.stories.tsx", + "src/cli/components/Summary.tsx", + "src/cli/components/TaskItem.stories.tsx", + "src/cli/components/TaskItem.tsx", + "src/cli/components/mod.ts", + "src/cli/components/tokens.ts", + "src/cli/context.ts", + "src/cli/errors.ts", + "src/cli/mod.ts", + "src/cli/observability.ts", + "src/cli/pin.integration.test.ts", + "src/cli/prompt-select-pty-fixture.ts", + "src/cli/prompt-select-pty.test.ts", + "src/cli/renderers/AddOutput/app.ts", + "src/cli/renderers/AddOutput/mod.ts", + "src/cli/renderers/AddOutput/schema.ts", + "src/cli/renderers/AddOutput/stories/Errors.stories.tsx", + "src/cli/renderers/AddOutput/stories/Success.stories.tsx", + "src/cli/renderers/AddOutput/stories/_fixtures.ts", + "src/cli/renderers/AddOutput/view.tsx", + "src/cli/renderers/DepsOutput/app.ts", + "src/cli/renderers/DepsOutput/mod.ts", + "src/cli/renderers/DepsOutput/schema.ts", + "src/cli/renderers/DepsOutput/stories/Basic.stories.tsx", + "src/cli/renderers/DepsOutput/stories/_fixtures.ts", + "src/cli/renderers/DepsOutput/view.tsx", + "src/cli/renderers/EnvOutput/app.ts", + "src/cli/renderers/EnvOutput/mod.ts", + "src/cli/renderers/EnvOutput/schema.ts", + "src/cli/renderers/EnvOutput/view.tsx", + "src/cli/renderers/ExecOutput/app.ts", + "src/cli/renderers/ExecOutput/mod.ts", + "src/cli/renderers/ExecOutput/schema.ts", + "src/cli/renderers/ExecOutput/stories/Complete.stories.tsx", + "src/cli/renderers/ExecOutput/stories/Errors.stories.tsx", + "src/cli/renderers/ExecOutput/stories/Running.stories.tsx", + "src/cli/renderers/ExecOutput/stories/_fixtures.ts", + "src/cli/renderers/ExecOutput/view.tsx", + "src/cli/renderers/GenerateOutput/app.ts", + "src/cli/renderers/GenerateOutput/mod.ts", + "src/cli/renderers/GenerateOutput/schema.ts", + "src/cli/renderers/GenerateOutput/view.tsx", + "src/cli/renderers/InitOutput/app.ts", + "src/cli/renderers/InitOutput/mod.ts", + "src/cli/renderers/InitOutput/schema.ts", + "src/cli/renderers/InitOutput/view.tsx", + "src/cli/renderers/LsOutput/app.ts", + "src/cli/renderers/LsOutput/mod.ts", + "src/cli/renderers/LsOutput/schema.ts", + "src/cli/renderers/LsOutput/stories/Basic.stories.tsx", + "src/cli/renderers/LsOutput/stories/Nested.stories.tsx", + "src/cli/renderers/LsOutput/stories/Sources.stories.tsx", + "src/cli/renderers/LsOutput/stories/_fixtures.ts", + "src/cli/renderers/LsOutput/view.tsx", + "src/cli/renderers/PinOutput/app.ts", + "src/cli/renderers/PinOutput/mod.ts", + "src/cli/renderers/PinOutput/schema.ts", + "src/cli/renderers/PinOutput/stories/Errors.stories.tsx", + "src/cli/renderers/PinOutput/stories/Success.stories.tsx", + "src/cli/renderers/PinOutput/stories/Warnings.stories.tsx", + "src/cli/renderers/PinOutput/stories/_fixtures.ts", + "src/cli/renderers/PinOutput/view.tsx", + "src/cli/renderers/PushRefsOutput/app.ts", + "src/cli/renderers/PushRefsOutput/mod.ts", + "src/cli/renderers/PushRefsOutput/schema.ts", + "src/cli/renderers/PushRefsOutput/stories/Errors.stories.tsx", + "src/cli/renderers/PushRefsOutput/stories/Results.stories.tsx", + "src/cli/renderers/PushRefsOutput/stories/_fixtures.ts", + "src/cli/renderers/PushRefsOutput/view.tsx", + "src/cli/renderers/RootOutput/app.ts", + "src/cli/renderers/RootOutput/mod.ts", + "src/cli/renderers/RootOutput/schema.ts", + "src/cli/renderers/RootOutput/stories/Errors.stories.tsx", + "src/cli/renderers/RootOutput/stories/Success.stories.tsx", + "src/cli/renderers/RootOutput/stories/_fixtures.ts", + "src/cli/renderers/RootOutput/view.tsx", + "src/cli/renderers/StatusOutput/app.ts", + "src/cli/renderers/StatusOutput/mod.ts", + "src/cli/renderers/StatusOutput/schema.ts", + "src/cli/renderers/StatusOutput/stories/Basic.stories.tsx", + "src/cli/renderers/StatusOutput/stories/Complex.stories.tsx", + "src/cli/renderers/StatusOutput/stories/LockIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/RefIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/WorktreeIssues.stories.tsx", + "src/cli/renderers/StatusOutput/stories/_fixtures.ts", + "src/cli/renderers/StatusOutput/view.tsx", + "src/cli/renderers/StoreOutput/app.ts", + "src/cli/renderers/StoreOutput/mod.ts", + "src/cli/renderers/StoreOutput/schema.ts", + "src/cli/renderers/StoreOutput/stories/Add.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Fetch.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Fix.stories.tsx", + "src/cli/renderers/StoreOutput/stories/GC.stories.tsx", + "src/cli/renderers/StoreOutput/stories/List.stories.tsx", + "src/cli/renderers/StoreOutput/stories/Status.stories.tsx", + "src/cli/renderers/StoreOutput/stories/WorktreeNew.stories.tsx", + "src/cli/renderers/StoreOutput/stories/_fixtures.ts", + "src/cli/renderers/StoreOutput/view.tsx", + "src/cli/renderers/SyncOutput/app.ts", + "src/cli/renderers/SyncOutput/mod.ts", + "src/cli/renderers/SyncOutput/schema.ts", + "src/cli/renderers/SyncOutput/stories/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/apply/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/apply/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/fetch/Issues.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/LockSync.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/Nested.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/fetch/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/lock/Results.stories.tsx", + "src/cli/renderers/SyncOutput/stories/lock/_fixtures.ts", + "src/cli/renderers/SyncOutput/stories/preflight/PreflightFailed.stories.tsx", + "src/cli/renderers/SyncOutput/ui.ts", + "src/cli/renderers/SyncOutput/view.tsx", + "src/cli/renderers/_story-constants.ts", + "src/cli/renderers/mod.ts", + "src/cli/status.integration.test.ts", + "src/cli/store-gc-cold.integration.test.ts", + "src/cli/store-gc-otel.integration.test.ts", + "src/cli/store.integration.test.ts", + "src/cli/sync.integration.test.ts", + "src/git.contract.ts", + "src/lib/config.ts", + "src/lib/config.unit.test.ts", + "src/lib/generators/generators.unit.test.ts", + "src/lib/generators/mod.ts", + "src/lib/generators/schema.ts", + "src/lib/generators/vscode.ts", + "src/lib/git-memory.integration.test.ts", + "src/lib/git-streaming-parsers.integration.test.ts", + "src/lib/git-timeout.integration.test.ts", + "src/lib/git.ts", + "src/lib/git.unit.test.ts", + "src/lib/issues.ts", + "src/lib/json-wire-baseline.test.ts", + "src/lib/lock.ts", + "src/lib/lock.unit.test.ts", + "src/lib/megarepo-traversal.ts", + "src/lib/megarepo-traversal.unit.test.ts", + "src/lib/nix-lock/flake-url.ts", + "src/lib/nix-lock/flake-url.unit.test.ts", + "src/lib/nix-lock/input-discovery.ts", + "src/lib/nix-lock/input-discovery.unit.test.ts", + "src/lib/nix-lock/matcher.ts", + "src/lib/nix-lock/mod.ts", + "src/lib/nix-lock/mod.unit.test.ts", + "src/lib/nix-lock/schema.ts", + "src/lib/nix-lock/schema.unit.test.ts", + "src/lib/nix-lock/source-rewriter.ts", + "src/lib/nix-lock/source-rewriter.unit.test.ts", + "src/lib/observability.ts", + "src/lib/ref.ts", + "src/lib/ref.unit.test.ts", + "src/lib/source-policy.ts", + "src/lib/source-policy.unit.test.ts", + "src/lib/store-archive.integration.test.ts", + "src/lib/store-archive.ts", + "src/lib/store-fs-atomic.ts", + "src/lib/store-fs-atomic.unit.test.ts", + "src/lib/store-gc-config.ts", + "src/lib/store-gc-config.unit.test.ts", + "src/lib/store-gc-observations.ts", + "src/lib/store-gc-observations.unit.test.ts", + "src/lib/store-hygiene.ts", + "src/lib/store-hygiene.unit.test.ts", + "src/lib/store-liveness.integration.test.ts", + "src/lib/store-liveness.ts", + "src/lib/store-lock.ts", + "src/lib/store-lock.unit.test.ts", + "src/lib/store-lossless.integration.test.ts", + "src/lib/store-lossless.ts", + "src/lib/store-path.ts", + "src/lib/store-path.unit.test.ts", + "src/lib/store-pr-state.ts", + "src/lib/store-pr-state.unit.test.ts", + "src/lib/store-worktree-policy.ts", + "src/lib/store-worktree-policy.unit.test.ts", + "src/lib/store.ts", + "src/lib/sync/member.ts", + "src/lib/sync/member.unit.test.ts", + "src/lib/sync/mod.ts", + "src/lib/sync/schema.ts", + "src/lib/sync/types.ts", + "src/lib/version.ts", + "src/megarepo.contract.ts", + "src/mod.ts", + "src/nix.contract.ts", + "src/test-utils/consoleCapture.ts", + "src/test-utils/git-env-setup.ts", + "src/test-utils/json.ts", + "src/test-utils/memory-probe.ts", + "src/test-utils/mod.ts", + "src/test-utils/setup.ts", + "src/test-utils/store-setup.integration.test.ts", + "src/test-utils/store-setup.ts", + "tsconfig.json", + ], + workspace_sources = [ + "//packages/@overeng/tui-core:project_sources", + "//packages/@overeng:content-address_project_sources", + "//packages/@overeng:effect-distributed-lock_project_sources", + "//packages/@overeng:effect-path_project_sources", + "//packages/@overeng:kdl-effect_project_sources", + "//packages/@overeng:kdl_project_sources", + "//packages/@overeng:otel-contract_project_sources", + "//packages/@overeng:tui-react_project_sources", + "//packages/@overeng:utils-dev_project_sources", + "//packages/@overeng:utils_project_sources", + ], + workspace_source_prefixes = { + "//packages/@overeng/tui-core:project_sources": "packages/@overeng/tui-core", + "//packages/@overeng:content-address_project_sources": "packages/@overeng", + "//packages/@overeng:effect-distributed-lock_project_sources": "packages/@overeng", + "//packages/@overeng:effect-path_project_sources": "packages/@overeng", + "//packages/@overeng:kdl-effect_project_sources": "packages/@overeng", + "//packages/@overeng:kdl_project_sources": "packages/@overeng", + "//packages/@overeng:otel-contract_project_sources": "packages/@overeng", + "//packages/@overeng:tui-react_project_sources": "packages/@overeng", + "//packages/@overeng:utils-dev_project_sources": "packages/@overeng", + "//packages/@overeng:utils_project_sources": "packages/@overeng", + }, +) + +typescript_cli( + name = "mr", + package_path = "packages/@overeng/megarepo", + entry = "packages/@overeng/megarepo/bin/mr.ts", + binary_name = "mr", + platform = "x86_64-linux", + srcs = [ + "bin/mr.ts", + "package.json", + "src/buck2-declared-unreachable-fixture.ts", + "src/cli/commands/add.ts", + "src/cli/commands/apply.ts", + "src/cli/commands/check.ts", + "src/cli/commands/config/mod.ts", + "src/cli/commands/config/push-refs.ts", + "src/cli/commands/deps.ts", + "src/cli/commands/engine.ts", + "src/cli/commands/env.ts", + "src/cli/commands/exec.ts", + "src/cli/commands/fetch.ts", + "src/cli/commands/generate/mod.ts", + "src/cli/commands/init.ts", + "src/cli/commands/lock.ts", + "src/cli/commands/ls.ts", + "src/cli/commands/mod.ts", + "src/cli/commands/pin.ts", + "src/cli/commands/root.ts", + "src/cli/commands/status.ts", + "src/cli/commands/store/mod.ts", + "src/cli/components/Header.tsx", + "src/cli/components/LogLine.tsx", + "src/cli/components/MemberRow.tsx", + "src/cli/components/Scope.tsx", + "src/cli/components/Separator.tsx", + "src/cli/components/StatusIcon.tsx", + "src/cli/components/Summary.tsx", + "src/cli/components/TaskItem.tsx", + "src/cli/components/mod.ts", + "src/cli/components/tokens.ts", + "src/cli/context.ts", + "src/cli/errors.ts", + "src/cli/mod.ts", + "src/cli/observability.ts", + "src/cli/renderers/AddOutput/app.ts", + "src/cli/renderers/AddOutput/mod.ts", + "src/cli/renderers/AddOutput/schema.ts", + "src/cli/renderers/AddOutput/view.tsx", + "src/cli/renderers/DepsOutput/app.ts", + "src/cli/renderers/DepsOutput/mod.ts", + "src/cli/renderers/DepsOutput/schema.ts", + "src/cli/renderers/DepsOutput/view.tsx", + "src/cli/renderers/EnvOutput/app.ts", + "src/cli/renderers/EnvOutput/mod.ts", + "src/cli/renderers/EnvOutput/schema.ts", + "src/cli/renderers/EnvOutput/view.tsx", + "src/cli/renderers/ExecOutput/app.ts", + "src/cli/renderers/ExecOutput/mod.ts", + "src/cli/renderers/ExecOutput/schema.ts", + "src/cli/renderers/ExecOutput/view.tsx", + "src/cli/renderers/GenerateOutput/app.ts", + "src/cli/renderers/GenerateOutput/mod.ts", + "src/cli/renderers/GenerateOutput/schema.ts", + "src/cli/renderers/GenerateOutput/view.tsx", + "src/cli/renderers/InitOutput/app.ts", + "src/cli/renderers/InitOutput/mod.ts", + "src/cli/renderers/InitOutput/schema.ts", + "src/cli/renderers/InitOutput/view.tsx", + "src/cli/renderers/LsOutput/app.ts", + "src/cli/renderers/LsOutput/mod.ts", + "src/cli/renderers/LsOutput/schema.ts", + "src/cli/renderers/LsOutput/view.tsx", + "src/cli/renderers/PinOutput/app.ts", + "src/cli/renderers/PinOutput/mod.ts", + "src/cli/renderers/PinOutput/schema.ts", + "src/cli/renderers/PinOutput/view.tsx", + "src/cli/renderers/PushRefsOutput/app.ts", + "src/cli/renderers/PushRefsOutput/mod.ts", + "src/cli/renderers/PushRefsOutput/schema.ts", + "src/cli/renderers/PushRefsOutput/view.tsx", + "src/cli/renderers/RootOutput/app.ts", + "src/cli/renderers/RootOutput/mod.ts", + "src/cli/renderers/RootOutput/schema.ts", + "src/cli/renderers/RootOutput/view.tsx", + "src/cli/renderers/StatusOutput/app.ts", + "src/cli/renderers/StatusOutput/mod.ts", + "src/cli/renderers/StatusOutput/schema.ts", + "src/cli/renderers/StatusOutput/view.tsx", + "src/cli/renderers/StoreOutput/app.ts", + "src/cli/renderers/StoreOutput/mod.ts", + "src/cli/renderers/StoreOutput/schema.ts", + "src/cli/renderers/StoreOutput/view.tsx", + "src/cli/renderers/SyncOutput/app.ts", + "src/cli/renderers/SyncOutput/mod.ts", + "src/cli/renderers/SyncOutput/schema.ts", + "src/cli/renderers/SyncOutput/ui.ts", + "src/cli/renderers/SyncOutput/view.tsx", + "src/cli/renderers/_story-constants.ts", + "src/cli/renderers/mod.ts", + "src/git.contract.ts", + "src/lib/config.ts", + "src/lib/generators/mod.ts", + "src/lib/generators/schema.ts", + "src/lib/generators/vscode.ts", + "src/lib/git.ts", + "src/lib/issues.ts", + "src/lib/lock.ts", + "src/lib/megarepo-traversal.ts", + "src/lib/nix-lock/flake-url.ts", + "src/lib/nix-lock/input-discovery.ts", + "src/lib/nix-lock/matcher.ts", + "src/lib/nix-lock/mod.ts", + "src/lib/nix-lock/schema.ts", + "src/lib/nix-lock/source-rewriter.ts", + "src/lib/observability.ts", + "src/lib/ref.ts", + "src/lib/source-policy.ts", + "src/lib/store-archive.ts", + "src/lib/store-fs-atomic.ts", + "src/lib/store-gc-config.ts", + "src/lib/store-gc-observations.ts", + "src/lib/store-hygiene.ts", + "src/lib/store-liveness.ts", + "src/lib/store-lock.ts", + "src/lib/store-lossless.ts", + "src/lib/store-path.ts", + "src/lib/store-pr-state.ts", + "src/lib/store-worktree-policy.ts", + "src/lib/store.ts", + "src/lib/sync/member.ts", + "src/lib/sync/mod.ts", + "src/lib/sync/schema.ts", + "src/lib/sync/types.ts", + "src/lib/version.ts", + "src/megarepo.contract.ts", + "src/mod.ts", + "src/nix.contract.ts", + ], + workspace_sources = [ + "//packages/@overeng/tui-core:production_sources", + "//packages/@overeng:content-address_production_sources", + "//packages/@overeng:effect-distributed-lock_production_sources", + "//packages/@overeng:effect-path_production_sources", + "//packages/@overeng:kdl-effect_production_sources", + "//packages/@overeng:kdl_production_sources", + "//packages/@overeng:otel-contract_production_sources", + "//packages/@overeng:tui-react_production_sources", + "//packages/@overeng:utils_production_sources", + ], + workspace_source_prefixes = { + "//packages/@overeng/tui-core:production_sources": "packages/@overeng/tui-core", + "//packages/@overeng:content-address_production_sources": "packages/@overeng", + "//packages/@overeng:effect-distributed-lock_production_sources": "packages/@overeng", + "//packages/@overeng:effect-path_production_sources": "packages/@overeng", + "//packages/@overeng:kdl-effect_production_sources": "packages/@overeng", + "//packages/@overeng:kdl_production_sources": "packages/@overeng", + "//packages/@overeng:otel-contract_production_sources": "packages/@overeng", + "//packages/@overeng:tui-react_production_sources": "packages/@overeng", + "//packages/@overeng:utils_production_sources": "packages/@overeng", + }, +) + +filegroup( + name = "mr_quality", + srcs = [":mr", ":typecheck"], + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/megarepo/BUCK.genie.ts b/packages/@overeng/megarepo/BUCK.genie.ts new file mode 100644 index 000000000..9272f8d2b --- /dev/null +++ b/packages/@overeng/megarepo/BUCK.genie.ts @@ -0,0 +1,179 @@ +import { readdirSync } from 'node:fs' +import { extname, join, posix } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { createGenieOutput } from '../genie/src/runtime/core.ts' +import { workspaceName, workspacePackages } from './buck2/workspace-packages.ts' +import megarepoPackage from './package.json.genie.ts' +import megarepoTsconfig from './tsconfig.json.genie.ts' + +const packageRoot = fileURLToPath(new URL('./', import.meta.url)) +const extensions = new Set(['.cts', '.mts', '.ts', '.tsx']) +const compareStrings = ({ left, right }: { left: string; right: string }): number => + left < right ? -1 : left > right ? 1 : 0 +const excludedFromProduct = (path: string): boolean => + path.includes('/stories/') || + path.includes('/test-utils/') || + path.includes('.test.') || + path.includes('.stories.') || + path.endsWith('prompt-select-pty-fixture.ts') + +const discover = ({ + directory, + productOnly, +}: { + directory: string + productOnly: boolean +}): readonly string[] => { + const sources: string[] = [] + const walk = (relative: string): void => { + for (const entry of readdirSync(join(packageRoot, relative), { withFileTypes: true }).toSorted( + (left, right) => compareStrings({ left: left.name, right: right.name }), + )) { + if (entry.isSymbolicLink() === true) + throw new Error(`Refusing source symlink: ${relative}/${entry.name}`) + const path = posix.join(relative, entry.name) + if (entry.isDirectory() === true) walk(path) + else if ( + entry.isFile() === true && + extensions.has(extname(entry.name)) === true && + (productOnly === false || excludedFromProduct(path) === false) + ) + sources.push(path) + } + } + walk(directory) + return sources +} + +const checkSources = [ + ...discover({ directory: 'bin', productOnly: false }), + ...discover({ directory: 'src', productOnly: false }), + 'package.json', + 'tsconfig.json', +].toSorted((left, right) => compareStrings({ left, right })) +const runtimeSources = [ + ...discover({ directory: 'bin', productOnly: true }), + ...discover({ directory: 'src', productOnly: true }), + 'package.json', +].toSorted((left, right) => compareStrings({ left, right })) +const labelFor = ({ name, role }: { name: string; role: 'production' | 'project' }): string => + name === 'tui-core' + ? `//packages/@overeng/tui-core:${role}_sources` + : `//packages/@overeng:${name}_${role}_sources` +type TsconfigOutput = { + readonly data: { readonly references?: readonly { readonly path: string }[] } +} +const referenceNames = (tsconfig: TsconfigOutput): readonly string[] => + (tsconfig.data.references ?? []).map(({ path }) => path.replace(/^\.\.\//u, '')) +const projectReferenceNames = (): readonly string[] => { + const pending = [...referenceNames(megarepoTsconfig)] + const seen = new Set() + while (pending.length > 0) { + const referenceName = pending.pop()! + const name = workspaceName(`@overeng/${referenceName}`) + if (name === undefined) + throw new Error(`Unknown workspace tsconfig reference: ${referenceName}`) + if (seen.has(name) === true) continue + seen.add(name) + pending.push(...referenceNames(workspacePackages[name].tsconfig)) + } + return [...seen] + .map((name) => name.slice('@overeng/'.length)) + .toSorted((left, right) => compareStrings({ left, right })) +} +const runtimeWorkspacePackageNames = (): readonly string[] => { + const pending = Object.keys(megarepoPackage.data.dependencies ?? {}) + const seen = new Set() + while (pending.length > 0) { + const specifier = pending.pop()! + const name = workspaceName(specifier) + if (name === undefined) { + if (specifier.startsWith('@overeng/') === true) + throw new Error(`Unknown workspace package dependency: ${specifier}`) + continue + } + if (seen.has(name) === true) continue + seen.add(name) + pending.push(...Object.keys(workspacePackages[name].packageJson.data.dependencies ?? {})) + } + return [...seen].map((name) => name.slice('@overeng/'.length)) +} +const checkWorkspaceSources = projectReferenceNames() + .map((name) => labelFor({ name, role: 'project' })) + .toSorted((left, right) => compareStrings({ left, right })) +const runtimeWorkspaceSources = runtimeWorkspacePackageNames() + .map((name) => labelFor({ name, role: 'production' })) + .toSorted((left, right) => compareStrings({ left, right })) +const prefixForLabel = (label: string): string => + label.includes('/tui-core:') === true ? 'packages/@overeng/tui-core' : 'packages/@overeng' +const renderList = (values: readonly string[]): string => + values.map((value) => ` ${JSON.stringify(value)},`).join('\n') +const renderPrefixes = (labels: readonly string[]): string => + labels + .map((label) => ` ${JSON.stringify(label)}: ${JSON.stringify(prefixForLabel(label))},`) + .join('\n') + +const rendered = `# Role closures derive from package.json.genie.ts and tsconfig.json.genie.ts. +load("//buck2:typescript.bzl", "typescript_cli", "typescript_project_check") + +filegroup( + name = "production_sources", + srcs = [ +${renderList(runtimeSources)} + ], + visibility = ["PUBLIC"], +) + +filegroup( + name = "project_sources", + srcs = [ +${renderList(checkSources)} + ], + visibility = ["PUBLIC"], +) + +typescript_project_check( + name = "typecheck", + package_path = "packages/@overeng/megarepo", + platform = "x86_64-linux", + tsconfig = "packages/@overeng/megarepo/tsconfig.json", + srcs = [ +${renderList(checkSources)} + ], + workspace_sources = [ +${renderList(checkWorkspaceSources)} + ], + workspace_source_prefixes = { +${renderPrefixes(checkWorkspaceSources)} + }, +) + +typescript_cli( + name = "mr", + package_path = "packages/@overeng/megarepo", + entry = "packages/@overeng/megarepo/bin/mr.ts", + binary_name = "mr", + platform = "x86_64-linux", + srcs = [ +${renderList(runtimeSources)} + ], + workspace_sources = [ +${renderList(runtimeWorkspaceSources)} + ], + workspace_source_prefixes = { +${renderPrefixes(runtimeWorkspaceSources)} + }, +) + +filegroup( + name = "mr_quality", + srcs = [":mr", ":typecheck"], + visibility = ["PUBLIC"], +) +` + +export default createGenieOutput({ + data: { checkSources, checkWorkspaceSources, runtimeSources, runtimeWorkspaceSources }, + stringify: () => rendered, +}) diff --git a/packages/@overeng/megarepo/buck2/workspace-packages.ts b/packages/@overeng/megarepo/buck2/workspace-packages.ts new file mode 100644 index 000000000..a03132cfa --- /dev/null +++ b/packages/@overeng/megarepo/buck2/workspace-packages.ts @@ -0,0 +1,47 @@ +import contentAddressPackage from '../../content-address/package.json.genie.ts' +import contentAddressTsconfig from '../../content-address/tsconfig.json.genie.ts' +import effectDistributedLockPackage from '../../effect-distributed-lock/package.json.genie.ts' +import effectDistributedLockTsconfig from '../../effect-distributed-lock/tsconfig.json.genie.ts' +import effectPathPackage from '../../effect-path/package.json.genie.ts' +import effectPathTsconfig from '../../effect-path/tsconfig.json.genie.ts' +import kdlEffectPackage from '../../kdl-effect/package.json.genie.ts' +import kdlEffectTsconfig from '../../kdl-effect/tsconfig.json.genie.ts' +import kdlPackage from '../../kdl/package.json.genie.ts' +import kdlTsconfig from '../../kdl/tsconfig.json.genie.ts' +import otelContractPackage from '../../otel-contract/package.json.genie.ts' +import otelContractTsconfig from '../../otel-contract/tsconfig.json.genie.ts' +import tuiCorePackage from '../../tui-core/package.json.genie.ts' +import tuiCoreTsconfig from '../../tui-core/tsconfig.json.genie.ts' +import tuiReactPackage from '../../tui-react/package.json.genie.ts' +import tuiReactTsconfig from '../../tui-react/tsconfig.json.genie.ts' +import utilsDevPackage from '../../utils-dev/package.json.genie.ts' +import utilsDevTsconfig from '../../utils-dev/tsconfig.json.genie.ts' +import utilsPackage from '../../utils/package.json.genie.ts' +import utilsTsconfig from '../../utils/tsconfig.json.genie.ts' + +/** Paired package and tsconfig Genie facets for workspace packages reachable by the mr graph. */ +export const workspacePackages = { + '@overeng/content-address': { + packageJson: contentAddressPackage, + tsconfig: contentAddressTsconfig, + }, + '@overeng/effect-distributed-lock': { + packageJson: effectDistributedLockPackage, + tsconfig: effectDistributedLockTsconfig, + }, + '@overeng/effect-path': { packageJson: effectPathPackage, tsconfig: effectPathTsconfig }, + '@overeng/kdl-effect': { packageJson: kdlEffectPackage, tsconfig: kdlEffectTsconfig }, + '@overeng/kdl': { packageJson: kdlPackage, tsconfig: kdlTsconfig }, + '@overeng/otel-contract': { packageJson: otelContractPackage, tsconfig: otelContractTsconfig }, + '@overeng/tui-core': { packageJson: tuiCorePackage, tsconfig: tuiCoreTsconfig }, + '@overeng/tui-react': { packageJson: tuiReactPackage, tsconfig: tuiReactTsconfig }, + '@overeng/utils-dev': { packageJson: utilsDevPackage, tsconfig: utilsDevTsconfig }, + '@overeng/utils': { packageJson: utilsPackage, tsconfig: utilsTsconfig }, +} as const + +/** Canonical package name admitted by the generated mr workspace graph. */ +export type WorkspacePackageName = keyof typeof workspacePackages + +/** Resolve a dependency specifier against the fail-closed workspace registry. */ +export const workspaceName = (specifier: string): WorkspacePackageName | undefined => + specifier in workspacePackages ? (specifier as WorkspacePackageName) : undefined diff --git a/packages/@overeng/megarepo/src/buck2-declared-unreachable-fixture.ts b/packages/@overeng/megarepo/src/buck2-declared-unreachable-fixture.ts new file mode 100644 index 000000000..e0da2d27c --- /dev/null +++ b/packages/@overeng/megarepo/src/buck2-declared-unreachable-fixture.ts @@ -0,0 +1,5 @@ +/** + * Benchmark-only production input proving the current package-level Buck closure is coarse. + * It is deliberately not imported by the mr entrypoint and must not gain runtime behavior. + */ +export type Buck2DeclaredUnreachableFixture = 'package-level-input-boundary' diff --git a/packages/@overeng/otel-scrape/BUCK b/packages/@overeng/otel-scrape/BUCK new file mode 100644 index 000000000..820bf4fcd --- /dev/null +++ b/packages/@overeng/otel-scrape/BUCK @@ -0,0 +1,41 @@ +# Generated file - DO NOT EDIT +# Source: BUCK.genie.ts + +# Projection source: packages/@overeng/otel-scrape/BUCK.genie.ts +# Projection schema version: 3 +# Projection generator: effect-utils/genie/buck2 +# Semantic fingerprint: sha256:b711181197a70b80b60246aa0b9b3198812a99801a743e858b7f784cdf67ba0a +# Semantic inputs: rust/Cargo.toml, rust/Cargo.lock, rust/reindeer.toml, rust/third-party/BUCK, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otel-scrape/src/**/*.rs +# Regenerate: devenv tasks run genie:run + +load("//packages/@overeng/otel-scrape/buck2:otel_scrape.bzl", "otel_scrape_targets") + +otel_scrape_targets( + binary_name = "otel-scrape", + binary_path = "src/main.rs", + dev_deps = [ + "//rust/third-party:tempfile", + ], + library_sources = [ + "src/adapters/deadnix.rs", + "src/adapters/mod.rs", + "src/adapters/node_cpuprofile.rs", + "src/adapters/oxlint.rs", + "src/adapters/vitest.rs", + "src/content_address.rs", + "src/lib.rs", + "src/telemetry_registry.gen.rs", + ], + edition = "2021", + library_name = "otel_scrape", + library_path = "src/lib.rs", + normal_deps = [ + "//rust/third-party:getrandom", + "//rust/third-party:libc", + "//rust/third-party:serde", + "//rust/third-party:serde_json", + "//rust/third-party:sha2", + ], + package_name = "otel-scrape", + package_version = "0.0.0", +) diff --git a/packages/@overeng/otel-scrape/BUCK.genie.ts b/packages/@overeng/otel-scrape/BUCK.genie.ts new file mode 100644 index 000000000..25aa51d1f --- /dev/null +++ b/packages/@overeng/otel-scrape/BUCK.genie.ts @@ -0,0 +1,203 @@ +import { existsSync, readdirSync } from 'node:fs' +import { extname, join, posix } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { + buck2ProjectionGenerator, + buck2ProjectionSchemaVersion, + buck2SemanticFingerprint, +} from '../../../genie/buck2/mod.ts' +import cargoWorkspace from '../../../rust/Cargo.toml' with { type: 'toml' } +import { createGenieOutput } from '../genie/src/runtime/core.ts' +import cargoManifest from './Cargo.toml' with { type: 'toml' } + +const root = fileURLToPath(new URL('./', import.meta.url)) +const compare = ([left, right]: readonly [string, string]): number => + left < right ? -1 : left > right ? 1 : 0 +const walk = (directory: string): readonly string[] => { + const result: string[] = [] + const visit = (relative: string): void => { + for (const entry of readdirSync(join(root, relative), { withFileTypes: true }).toSorted( + (a, b) => compare([a.name, b.name]), + )) { + if (entry.isSymbolicLink() === true) + throw new Error(`Refusing Buck input symlink: ${relative}`) + const path = posix.join(relative, entry.name) + if (entry.isDirectory() === true) visit(path) + else if (entry.isFile() === true) result.push(path) + } + } + visit(directory) + return result +} + +type CargoDependency = + | string + | { + readonly optional?: boolean + readonly package?: string + readonly workspace?: boolean + } +export const cargoDependencyLabel = ([name, request]: readonly [ + string, + CargoDependency, +]): string => { + if (typeof request !== 'string' && request.package !== undefined) + throw new Error(`Unsupported renamed Cargo dependency: ${name} -> ${request.package}`) + if (typeof request !== 'string' && request.optional === true) + throw new Error(`Unsupported optional Cargo dependency: ${name}`) + return `//rust/third-party:${name}` +} +const manifest = cargoManifest as { + readonly package?: { + readonly name?: string + readonly workspace?: string + readonly version?: { readonly workspace?: boolean } + readonly edition?: { readonly workspace?: boolean } + readonly build?: string | boolean + } + readonly lib?: { readonly name?: string; readonly path?: string } + readonly bin?: readonly { + readonly name?: string + readonly path?: string + readonly 'required-features'?: readonly string[] + }[] + readonly dependencies?: Readonly> + readonly 'dev-dependencies'?: Readonly> + readonly 'build-dependencies'?: Readonly> + readonly features?: Readonly> + readonly target?: unknown +} +const workspace = cargoWorkspace as { + readonly workspace?: { + readonly package?: { readonly version?: string; readonly edition?: string } + } +} +const requireValue = ({ + value, + field, +}: { + readonly value: T | undefined + readonly field: string +}): T => { + if (value === undefined) throw new Error(`Cargo metadata is missing ${field}`) + return value +} +export const resolveCargoTargetMetadata = (args: { + readonly defaultBuildScriptExists?: boolean + readonly manifest: typeof manifest + readonly workspace: typeof workspace +}) => { + const packageMetadata = requireValue({ value: args.manifest.package, field: 'package' }) + if (packageMetadata.workspace !== '../../../rust') + throw new Error('Unsupported Cargo workspace path') + if (packageMetadata.version?.workspace !== true || packageMetadata.edition?.workspace !== true) + throw new Error('Cargo package version and edition must inherit from the workspace') + if ( + (packageMetadata.build !== undefined && packageMetadata.build !== false) || + args.defaultBuildScriptExists === true + ) + throw new Error('Cargo build scripts are not supported by the OTEL Buck projection') + if (args.manifest['build-dependencies'] !== undefined) + throw new Error('Cargo build dependencies are not supported by the OTEL Buck projection') + if (args.manifest.target !== undefined) + throw new Error( + 'Target-conditioned Cargo dependencies are not supported by the OTEL Buck projection', + ) + if (Object.keys(args.manifest.features ?? {}).length > 0) + throw new Error('Cargo features are not supported by the OTEL Buck projection') + const library = requireValue({ value: args.manifest.lib, field: 'lib' }) + const binaries = requireValue({ value: args.manifest.bin, field: 'bin' }) + if (binaries.length !== 1) throw new Error('Exactly one Cargo binary is supported') + if ((binaries[0]?.['required-features']?.length ?? 0) > 0) + throw new Error('Cargo binary required-features are not supported by the OTEL Buck projection') + return { + binaryName: requireValue({ value: binaries[0]?.name, field: 'bin[0].name' }), + binaryPath: requireValue({ value: binaries[0]?.path, field: 'bin[0].path' }), + edition: requireValue({ + value: args.workspace.workspace?.package?.edition, + field: 'workspace.package.edition', + }), + libraryName: requireValue({ value: library.name, field: 'lib.name' }), + libraryPath: requireValue({ value: library.path, field: 'lib.path' }), + packageName: requireValue({ value: packageMetadata.name, field: 'package.name' }), + version: requireValue({ + value: args.workspace.workspace?.package?.version, + field: 'workspace.package.version', + }), + } +} +const { binaryName, binaryPath, edition, libraryName, libraryPath, packageName, version } = + resolveCargoTargetMetadata({ + defaultBuildScriptExists: existsSync(join(root, 'build.rs')), + manifest, + workspace, + }) +const rustSources = walk('src').filter((path) => extname(path) === '.rs') +if (rustSources.includes(binaryPath) === false) + throw new Error(`Cargo binary path is not a Rust source: ${binaryPath}`) +if (rustSources.includes(libraryPath) === false) + throw new Error(`Cargo library path is not a Rust source: ${libraryPath}`) +if (binaryPath === libraryPath) throw new Error('Cargo binary and library paths must be distinct') +const librarySources = rustSources.filter((path) => path !== binaryPath).toSorted(compare) +const list = librarySources.map((path) => ` ${JSON.stringify(path)},`).join('\n') +const dependencyLabels = (dependencies: Readonly> | undefined) => + Object.entries(dependencies ?? {}) + .map(cargoDependencyLabel) + .toSorted(compare) +const normalDependencies = dependencyLabels(manifest.dependencies) +const devDependencies = dependencyLabels(manifest['dev-dependencies']) +const renderLabels = (labels: readonly string[]) => + labels.map((label) => ` ${JSON.stringify(label)},`).join('\n') +const semanticData = { + devDependencies, + binaryName, + binaryPath, + edition, + libraryName, + libraryPath, + librarySources, + normalDependencies, + packageName, + package: 'packages/@overeng/otel-scrape', + targets: ['lib', 'otel-scrape', 'product', 'unit'], + version, +} +const semanticFingerprint = buck2SemanticFingerprint({ + generator: buck2ProjectionGenerator, + schemaVersion: buck2ProjectionSchemaVersion, + semanticData, +}) +const rendered = `# Projection source: packages/@overeng/otel-scrape/BUCK.genie.ts +# Projection schema version: ${buck2ProjectionSchemaVersion} +# Projection generator: ${buck2ProjectionGenerator} +# Semantic fingerprint: ${semanticFingerprint} +# Semantic inputs: rust/Cargo.toml, rust/Cargo.lock, rust/reindeer.toml, rust/third-party/BUCK, packages/@overeng/otel-scrape/Cargo.toml, packages/@overeng/otel-scrape/src/**/*.rs +# Regenerate: devenv tasks run genie:run + +load("//packages/@overeng/otel-scrape/buck2:otel_scrape.bzl", "otel_scrape_targets") + +otel_scrape_targets( + binary_name = ${JSON.stringify(binaryName)}, + binary_path = ${JSON.stringify(binaryPath)}, + dev_deps = [ +${renderLabels(devDependencies)} + ], + library_sources = [ +${list} + ], + edition = ${JSON.stringify(edition)}, + library_name = ${JSON.stringify(libraryName)}, + library_path = ${JSON.stringify(libraryPath)}, + normal_deps = [ +${renderLabels(normalDependencies)} + ], + package_name = ${JSON.stringify(packageName)}, + package_version = ${JSON.stringify(version)}, +) +` + +export default createGenieOutput({ + data: { ...semanticData, semanticFingerprint }, + stringify: () => rendered, +}) diff --git a/packages/@overeng/otel-scrape/BUCK.genie.unit.test.ts b/packages/@overeng/otel-scrape/BUCK.genie.unit.test.ts new file mode 100644 index 000000000..97cc28781 --- /dev/null +++ b/packages/@overeng/otel-scrape/BUCK.genie.unit.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, it } from 'vitest' + +import { cargoDependencyLabel, resolveCargoTargetMetadata } from './BUCK.genie.ts' + +const manifest = { + package: { + name: 'otel-scrape', + workspace: '../../../rust', + version: { workspace: true }, + edition: { workspace: true }, + }, + lib: { name: 'otel_scrape', path: 'src/lib.rs' }, + bin: [{ name: 'otel-scrape', path: 'src/main.rs' }], +} as const +const workspace = { workspace: { package: { version: '0.0.0', edition: '2021' } } } as const + +describe('OTEL Cargo-to-Buck target projection', () => { + it('resolves the supported package, library, binary, edition, and version', () => { + expect(resolveCargoTargetMetadata({ manifest, workspace })).toEqual({ + binaryName: 'otel-scrape', + binaryPath: 'src/main.rs', + edition: '2021', + libraryName: 'otel_scrape', + libraryPath: 'src/lib.rs', + packageName: 'otel-scrape', + version: '0.0.0', + }) + }) + + it.each([ + [ + 'multiple binaries', + { ...manifest, bin: [...manifest.bin, { name: 'other', path: 'src/other.rs' }] }, + ], + ['build script', { ...manifest, package: { ...manifest.package, build: 'build.rs' } }], + ['build dependencies', { ...manifest, 'build-dependencies': { cc: '1' } }], + ['target dependencies', { ...manifest, target: { cfg: {} } }], + ['features', { ...manifest, features: { default: [] } }], + [ + 'binary required-features', + { ...manifest, bin: [{ ...manifest.bin[0], 'required-features': ['cli'] }] }, + ], + ])('rejects unsupported %s', (_label, candidate) => { + expect(() => resolveCargoTargetMetadata({ manifest: candidate, workspace })).toThrow( + /not supported|Exactly one/u, + ) + }) + + it('rejects Cargo implicit build.rs convention', () => { + expect(() => + resolveCargoTargetMetadata({ defaultBuildScriptExists: true, manifest, workspace }), + ).toThrow('Cargo build scripts are not supported') + }) + + it('rejects renamed dependencies instead of silently changing Cargo semantics', () => { + expect(() => cargoDependencyLabel(['alias', { package: 'real-package' }])).toThrow( + 'Unsupported renamed Cargo dependency', + ) + }) + + it('rejects optional dependencies instead of projecting them unconditionally', () => { + expect(() => cargoDependencyLabel(['serde', { workspace: true, optional: true }])).toThrow( + 'Unsupported optional Cargo dependency', + ) + }) +}) diff --git a/packages/@overeng/otel-scrape/buck2/otel_scrape.bzl b/packages/@overeng/otel-scrape/buck2/otel_scrape.bzl new file mode 100644 index 000000000..2d7bf837e --- /dev/null +++ b/packages/@overeng/otel-scrape/buck2/otel_scrape.bzl @@ -0,0 +1,65 @@ +"""Native Rust graph for otel-scrape.""" + +load("@prelude//:prelude.bzl", "native") +load("//buck2:rust_product.bzl", "rust_build_product") + +_EXECUTION = ["//buck2/platforms:x86_64_linux_local_store_execution"] +_TARGET = [ + "prelude//abi/constraints:musl", + "prelude//cpu/constraints:x86_64", + "prelude//os/constraints:linux", + "//buck2/platforms:static", +] + +def otel_scrape_targets(binary_name, binary_path, dev_deps, edition, library_name, library_path, library_sources, normal_deps, package_name, package_version): + compile_identity = read_config("rust_toolchain", "compile_identity", "") + if len(compile_identity) != 71 or not compile_identity.startswith("sha256:"): + fail("rust_toolchain.compile_identity must be a Nix-authored sha256 identity") + common = { + "edition": edition, + "exec_compatible_with": _EXECUTION, + "target_compatible_with": _TARGET, + } + compile_env = { + "CARGO_PKG_NAME": package_name, + "CARGO_PKG_VERSION": package_version, + # The Nix-authored semantic identity is an explicit compile-action key + # input in addition to the immutable executable paths in the provider. + "EFFECT_UTILS_BUCK2_TOOLCHAIN_IDENTITY": compile_identity, + } + native.rust_library( + name = "lib", + crate = library_name, + crate_root = library_path, + srcs = library_sources, + deps = normal_deps, + env = compile_env, + visibility = ["PUBLIC"], + **common + ) + native.rust_binary( + name = binary_name, + crate = binary_name.replace("-", "_"), + crate_root = binary_path, + srcs = [binary_path], + deps = [":lib"], + env = compile_env, + visibility = ["PUBLIC"], + **common + ) + native.rust_test( + name = "unit", + crate = library_name + "_unit", + crate_root = library_path, + srcs = library_sources, + deps = normal_deps + dev_deps, + env = compile_env, + **common + ) + rust_build_product( + name = "product", + binary = ":" + binary_name, + binary_name = binary_name, + compile_identity = compile_identity, + visibility = ["PUBLIC"], + ) diff --git a/packages/@overeng/tui-core/BUCK b/packages/@overeng/tui-core/BUCK index 31baba2b1..afd1ff626 100644 --- a/packages/@overeng/tui-core/BUCK +++ b/packages/@overeng/tui-core/BUCK @@ -31,3 +31,15 @@ package_task( ], closure_descriptor = "buck2/typescript-input-plan.json", ) + +filegroup( + name = "production_sources", + srcs = glob(["src/**/*.ts", "src/**/*.tsx", "package.json", "tsconfig.json"], exclude = ["src/**/*.test.ts", "src/**/*.test.tsx"]), + visibility = ["PUBLIC"], +) + +filegroup( + name = "project_sources", + srcs = glob(["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts", "test/**/*.tsx", "package.json", "tsconfig.json"]), + visibility = ["PUBLIC"], +) diff --git a/packages/@overeng/tui-core/BUCK.genie.ts b/packages/@overeng/tui-core/BUCK.genie.ts index 6978bb475..13b24a683 100644 --- a/packages/@overeng/tui-core/BUCK.genie.ts +++ b/packages/@overeng/tui-core/BUCK.genie.ts @@ -1,4 +1,5 @@ import { buck2Projection } from '../../../genie/buck2/mod.ts' +import { createGenieOutput } from '../genie/src/runtime/core.ts' import { discoverPackageSources, packagePath, @@ -9,7 +10,7 @@ import { const target = targetForSources(discoverPackageSources(new URL('./', import.meta.url))) -export default buck2Projection.packageFile({ +const packageOutput = buck2Projection.packageFile({ packagePath, macro: { load: '//buck2:package_targets.bzl', @@ -20,3 +21,11 @@ export default buck2Projection.packageFile({ regenerationCommand, source: 'packages/@overeng/tui-core/BUCK.genie.ts', }) + +export default createGenieOutput({ + data: { + package: packageOutput.data, + }, + stringify: (context) => + `${packageOutput.stringify(context)}\nfilegroup(\n name = "production_sources",\n srcs = glob(["src/**/*.ts", "src/**/*.tsx", "package.json", "tsconfig.json"], exclude = ["src/**/*.test.ts", "src/**/*.test.tsx"]),\n visibility = ["PUBLIC"],\n)\n\nfilegroup(\n name = "project_sources",\n srcs = glob(["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts", "test/**/*.tsx", "package.json", "tsconfig.json"]),\n visibility = ["PUBLIC"],\n)\n`, +}) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 72a269da1..8badc122a 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -249,6 +249,20 @@ dependencies = [ "sha2", ] +[[package]] +name = "buck2-typescript-product" +version = "0.0.0" +dependencies = [ + "base64", + "buck2-tool-core", + "clap", + "serde_json", + "sha2", + "tar", + "tempfile", + "walkdir", +] + [[package]] name = "bumpalo" version = "3.20.3" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 66fa44bb9..e1dd3d613 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -6,6 +6,7 @@ members = [ "buck2-tools/core", "buck2-tools/closure-tool", "buck2-tools/package-evidence", + "buck2-tools/typescript-product", "buck2-tools/portable-toolchain", "buck2-tools/portable-toolchain-fixture", ] diff --git a/rust/buck2-tools/package-evidence/src/main.rs b/rust/buck2-tools/package-evidence/src/main.rs index d99098603..d89aa0e12 100644 --- a/rust/buck2-tools/package-evidence/src/main.rs +++ b/rust/buck2-tools/package-evidence/src/main.rs @@ -22,7 +22,24 @@ struct Cli { #[derive(Subcommand)] enum Command { - Package(PackageArgs), + Package(Box), + Product(ProductArgs), +} + +#[derive(Args)] +struct ProductArgs { + #[arg(long)] + binary: PathBuf, + #[arg(long = "binary-name")] + binary_name: String, + #[arg(long)] + target: String, + #[arg(long = "toolchain-identity")] + toolchain_identity: String, + #[arg(long)] + archive: PathBuf, + #[arg(long)] + descriptor: PathBuf, } #[derive(Args)] @@ -312,9 +329,59 @@ fn hex_to_bytes(value: &str) -> Vec { .map(|index| u8::from_str_radix(&value[index..index + 2], 16).unwrap()) .collect() } + +fn product(args: ProductArgs) -> ToolResult<()> { + let name = nix_name(&args.binary_name, "binary name")?; + let target = safe_text(&args.target, "target")?; + let toolchain = safe_text(&args.toolchain_identity, "toolchain identity")?; + if !toolchain.starts_with("sha256:") || toolchain.len() != 71 { + return Err(ToolError::new( + "BUCK2_PRODUCT_TOOLCHAIN", + "toolchain identity must be a Nix-authored sha256 identity", + )); + } + let binary = fs::read(&args.binary) + .map_err(|error| ToolError::new("BUCK2_PRODUCT_INPUT", error.to_string()))?; + let archive_file = fs::File::create(&args.archive) + .map_err(|error| ToolError::new("BUCK2_PRODUCT_IO", error.to_string()))?; + let mut builder = Builder::new(archive_file); + add_member(&mut builder, "bin", None, 0o555)?; + add_member(&mut builder, &format!("bin/{name}"), Some(&binary), 0o555)?; + builder + .finish() + .map_err(|error| ToolError::new("BUCK2_PRODUCT_TAR", error.to_string()))?; + drop(builder); + let archive = fs::read(&args.archive) + .map_err(|error| ToolError::new("BUCK2_PRODUCT_IO", error.to_string()))?; + let digest = sha256_bytes(&archive); + let descriptor = json!({ + "entrypoints": [format!("bin/{name}")], + "name": name, + "payload": { + "digest": {"algorithm": "sha256", "sri": format!("sha256-{}", STANDARD.encode(hex_to_bytes(&digest)))}, + "file": "artifact.tar", + "format": "tar", + "sizeBytes": archive.len(), + }, + "platform": {"abi": "musl", "architecture": "x86_64", "os": "linux"}, + "runtime": {"inspectionContract": "elf-static/v1", "kind": "self-contained"}, + "schema": "buck-build-product/v1", + "semanticProvenance": { + "recipe": "rust-static-binary/v1", + "target": target, + "toolchain": toolchain, + }, + }); + let descriptor_bytes = serde_json::to_vec(&descriptor) + .map_err(|error| ToolError::new("BUCK2_PRODUCT_JSON", error.to_string()))?; + fs::write(&args.descriptor, descriptor_bytes) + .map_err(|error| ToolError::new("BUCK2_PRODUCT_IO", error.to_string())) +} + fn run() -> ToolResult<()> { match Cli::parse().command { - Command::Package(args) => package(args), + Command::Package(args) => package(*args), + Command::Product(args) => product(args), } } fn main() { @@ -392,7 +459,9 @@ mod tests { "descriptor.json", ]) .unwrap(); - let Command::Package(args) = cli.command; + let Command::Package(args) = cli.command else { + panic!("expected package command") + }; assert_eq!(args.sources, [PathBuf::from("a.ts"), PathBuf::from("b.ts")]); assert_eq!(args.configs, [PathBuf::from("tsconfig.json")]); } diff --git a/rust/buck2-tools/typescript-product/Cargo.toml b/rust/buck2-tools/typescript-product/Cargo.toml new file mode 100644 index 000000000..a22743a66 --- /dev/null +++ b/rust/buck2-tools/typescript-product/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "buck2-typescript-product" +workspace = "../.." +version.workspace = true +edition.workspace = true +license.workspace = true +publish = false + +[[bin]] +name = "buck2-typescript-product" +path = "src/main.rs" + +[dependencies] +base64 = "0.22" +buck2-tool-core = { path = "../core" } +clap = { version = "4", features = ["derive"] } +serde_json.workspace = true +sha2.workspace = true +tar = { version = "0.4", default-features = false } +tempfile.workspace = true +walkdir = "2" diff --git a/rust/buck2-tools/typescript-product/src/main.rs b/rust/buck2-tools/typescript-product/src/main.rs new file mode 100644 index 000000000..d15edf96d --- /dev/null +++ b/rust/buck2-tools/typescript-product/src/main.rs @@ -0,0 +1,606 @@ +use base64::{engine::general_purpose::STANDARD, Engine}; +use buck2_tool_core::{ + canonical_json, normalized_relative, safe_text, sha256_file, ToolError, ToolResult, +}; +use clap::{Args, Parser, Subcommand}; +use serde_json::json; +use sha2::{Digest, Sha256}; +use std::{ + collections::HashSet, + fs, + io::Cursor, + os::unix::fs::{symlink, PermissionsExt}, + path::{Path, PathBuf}, + process::Command, +}; +use tar::{Builder, EntryType, Header}; +use tempfile::tempdir; +use walkdir::WalkDir; + +#[derive(Parser)] +struct Cli { + #[command(subcommand)] + command: CommandKind, +} + +#[derive(Subcommand)] +enum CommandKind { + Check(CheckArgs), + Bundle(BundleArgs), +} + +#[derive(Args)] +struct CommonArgs { + #[arg(long = "dependency-root")] + dependency_root: PathBuf, + #[arg(long = "native-package")] + native_packages: Vec, + #[arg(long = "source-label")] + source_labels: Vec, + #[arg(long = "source")] + sources: Vec, + #[arg(long = "source-tree-prefix")] + source_tree_prefixes: Vec, + #[arg(long = "source-tree")] + source_trees: Vec, +} + +#[derive(Args)] +struct CheckArgs { + #[command(flatten)] + common: CommonArgs, + #[arg(long)] + tsgo: PathBuf, + #[arg(long)] + tsconfig: String, + #[arg(long)] + output: PathBuf, +} + +#[derive(Args)] +struct BundleArgs { + #[command(flatten)] + common: CommonArgs, + #[arg(long)] + bun: PathBuf, + #[arg(long)] + patchelf: PathBuf, + #[arg(long)] + entry: String, + #[arg(long = "binary-name")] + binary_name: String, + #[arg(long)] + output: PathBuf, + #[arg(long)] + archive: PathBuf, + #[arg(long)] + descriptor: PathBuf, + #[arg(long)] + target: String, + #[arg(long)] + platform: String, +} + +fn fail(code: &'static str, message: impl Into) -> ToolError { + ToolError::new(code, message) +} + +fn require_executable(path: &Path, name: &str) -> ToolResult<()> { + let metadata = fs::metadata(path) + .map_err(|error| fail("BUCK2_TS_TOOL", format!("{name} is unavailable: {error}")))?; + if !metadata.is_file() || metadata.permissions().mode() & 0o111 == 0 { + return Err(fail( + "BUCK2_TS_TOOL", + format!("{name} is not executable: {}", path.display()), + )); + } + Ok(()) +} + +fn pair<'a, T>( + left: &'a [String], + right: &'a [T], + role: &str, +) -> ToolResult> { + if left.len() != right.len() { + return Err(fail( + "BUCK2_TS_EDGES", + format!("{role} labels and artifacts must be paired"), + )); + } + Ok(left.iter().zip(right)) +} + +fn copy_file(source: &Path, destination: &Path) -> ToolResult<()> { + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent).map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + } + match fs::hard_link(source, destination) { + Ok(()) => Ok(()), + Err(_) => fs::copy(source, destination) + .map(|_| ()) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string())), + } +} + +fn copy_tree(source: &Path, destination: &Path, containment_root: &Path) -> ToolResult<()> { + if !source.is_dir() { + return Err(fail( + "BUCK2_TS_STAGE", + format!("source tree is not a directory: {}", source.display()), + )); + } + for entry in WalkDir::new(source).follow_links(false).into_iter() { + let entry = entry.map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + let relative = entry.path().strip_prefix(source).unwrap(); + if relative.as_os_str().is_empty() { + fs::create_dir_all(destination) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + } else if entry.file_type().is_dir() { + fs::create_dir_all(destination.join(relative)) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + } else if entry.file_type().is_file() { + copy_file(entry.path(), &destination.join(relative))?; + } else if entry.file_type().is_symlink() { + let target = fs::read_link(entry.path()) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + let resolved = fs::canonicalize(entry.path()).map_err(|error| { + fail( + "BUCK2_TS_DEPENDENCY_SYMLINK", + format!("dependency symlink is unresolved: {error}"), + ) + })?; + let canonical_source = fs::canonicalize(containment_root) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + if !resolved.starts_with(&canonical_source) { + return Err(fail( + "BUCK2_TS_DEPENDENCY_SYMLINK", + format!( + "dependency symlink escapes its declared closure: {} -> {}", + entry.path().display(), + target.display() + ), + )); + } + let output = destination.join(relative); + if let Some(parent) = output.parent() { + fs::create_dir_all(parent) + .map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + } + symlink(target, output).map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + } else { + return Err(fail( + "BUCK2_TS_STAGE", + "dependency tree contains an unsupported node", + )); + } + } + Ok(()) +} + +fn stage(common: &CommonArgs, workspace: &Path) -> ToolResult<()> { + let mut seen = HashSet::new(); + for (label, source) in pair(&common.source_labels, &common.sources, "source")? { + let label = normalized_relative(label, "source label")?; + if !seen.insert(label.clone()) { + return Err(fail( + "BUCK2_TS_DUPLICATE", + format!("duplicate staged source: {label}"), + )); + } + copy_file(source, &workspace.join(label))?; + } + for (prefix, tree) in pair( + &common.source_tree_prefixes, + &common.source_trees, + "source tree", + )? { + let prefix = normalized_relative(prefix, "source tree prefix")?; + for entry in WalkDir::new(tree) + .min_depth(1) + .follow_links(false) + .into_iter() + { + let entry = entry.map_err(|error| fail("BUCK2_TS_STAGE", error.to_string()))?; + if entry.file_type().is_symlink() { + return Err(fail( + "BUCK2_TS_STAGE", + format!( + "declared source tree contains a symlink: {}", + entry.path().display() + ), + )); + } + if !entry.file_type().is_file() { + continue; + } + let relative = entry + .path() + .strip_prefix(tree) + .unwrap() + .to_string_lossy() + .replace('\\', "/"); + let label = normalized_relative(&format!("{prefix}/{relative}"), "source tree member")?; + if !seen.insert(label.clone()) { + return Err(fail( + "BUCK2_TS_DUPLICATE", + format!("duplicate staged source: {label}"), + )); + } + copy_file(entry.path(), &workspace.join(label))?; + } + } + let modules = common.dependency_root.join("node_modules"); + if !modules.is_dir() { + return Err(fail("BUCK2_TS_DEPS", "dependency root has no node_modules")); + } + copy_tree( + &modules, + &workspace.join("node_modules"), + &common.dependency_root, + )?; + let package_layouts = common.dependency_root.join("packages"); + if package_layouts.is_dir() { + for entry in WalkDir::new(&package_layouts) + .follow_links(false) + .into_iter() + .filter_map(Result::ok) + { + if entry.file_type().is_dir() && entry.file_name() == "node_modules" { + let relative = entry + .path() + .parent() + .unwrap() + .strip_prefix(&common.dependency_root) + .unwrap(); + copy_tree( + entry.path(), + &workspace.join(relative).join("node_modules"), + &common.dependency_root, + )?; + } + } + } + for native in &common.native_packages { + let (name, source) = native + .split_once('=') + .ok_or_else(|| fail("BUCK2_TS_NATIVE", "native package must be NAME=PATH"))?; + let name = normalized_relative(name, "native package name")?; + let destination = workspace.join("node_modules").join(name); + if destination.exists() || destination.is_symlink() { + if destination.is_dir() && !destination.is_symlink() { + fs::remove_dir_all(&destination) + } else { + fs::remove_file(&destination) + } + .map_err(|error| fail("BUCK2_TS_NATIVE", error.to_string()))?; + } + symlink(source, destination).map_err(|error| fail("BUCK2_TS_NATIVE", error.to_string()))?; + } + Ok(()) +} + +fn run_tool(program: &Path, args: &[&str], cwd: &Path, home: &Path) -> ToolResult<()> { + let status = Command::new(program) + .args(args) + .current_dir(cwd) + .env_clear() + .env("HOME", home) + .env("PATH", "/nonexistent") + .env("DEVENV_TASK_PASSTHROUGH", "1") + .status() + .map_err(|error| fail("BUCK2_TS_EXEC", error.to_string()))?; + if !status.success() { + return Err(fail( + "BUCK2_TS_EXEC", + format!("{} exited with {status}", program.display()), + )); + } + Ok(()) +} + +fn check(args: CheckArgs) -> ToolResult<()> { + require_executable(&args.tsgo, "tsgo")?; + let tsconfig = normalized_relative(&args.tsconfig, "tsconfig")?; + let temp = tempdir().map_err(|error| fail("BUCK2_TS_TEMP", error.to_string()))?; + let workspace = temp.path().join("workspace"); + fs::create_dir(&workspace).map_err(|error| fail("BUCK2_TS_TEMP", error.to_string()))?; + stage(&args.common, &workspace)?; + if !workspace.join(&tsconfig).is_file() { + return Err(fail( + "BUCK2_TS_CONFIG", + "tsconfig is absent from the declared source graph", + )); + } + run_tool( + &args.tsgo, + &["--build", &tsconfig, "--force", "--pretty", "false"], + &workspace, + &temp.path().join("home"), + )?; + if let Some(parent) = args.output.parent() { + fs::create_dir_all(parent).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + } + fs::write( + args.output, + canonical_json( + &json!({"project":tsconfig,"schema":"effect-utils-buck2-typescript-check/v1"}), + )?, + ) + .map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string())) +} + +fn append_tar( + builder: &mut Builder, + name: &str, + bytes: Option<&[u8]>, + mode: u32, +) -> ToolResult<()> { + let mut header = Header::new_ustar(); + header.set_uid(0); + header.set_gid(0); + header.set_mtime(1); + header.set_mode(mode); + header + .set_username("") + .map_err(|error| fail("BUCK2_TS_TAR", error.to_string()))?; + header + .set_groupname("") + .map_err(|error| fail("BUCK2_TS_TAR", error.to_string()))?; + match bytes { + None => { + header.set_entry_type(EntryType::Directory); + header.set_size(0); + } + Some(value) => { + header.set_entry_type(EntryType::Regular); + header.set_size(value.len() as u64); + } + } + header.set_cksum(); + builder + .append_data(&mut header, name, Cursor::new(bytes.unwrap_or_default())) + .map_err(|error| fail("BUCK2_TS_TAR", error.to_string())) +} + +fn input_digest(args: &BundleArgs) -> ToolResult { + let mut digest = Sha256::new(); + digest.update(canonical_json(&json!({ + "binaryName": args.binary_name, "bun": args.bun, + "dependencyRoot": args.common.dependency_root, "entry": args.entry, + "nativePackages": args.common.native_packages, "patchelf": args.patchelf, + "platform": args.platform, "target": args.target, + }))?); + let mut inputs = + pair(&args.common.source_labels, &args.common.sources, "source")?.collect::>(); + inputs.sort_by_key(|(label, _)| *label); + for (label, path) in inputs { + digest.update(label.as_bytes()); + digest.update([0]); + digest.update(fs::read(path).map_err(|error| fail("BUCK2_TS_DIGEST", error.to_string()))?); + } + let mut trees = pair( + &args.common.source_tree_prefixes, + &args.common.source_trees, + "source tree", + )? + .collect::>(); + trees.sort_by_key(|(prefix, _)| *prefix); + for (prefix, tree) in trees { + let prefix = normalized_relative(prefix, "source tree prefix")?; + let mut members = WalkDir::new(tree) + .min_depth(1) + .follow_links(false) + .into_iter() + .map(|entry| entry.map_err(|error| fail("BUCK2_TS_DIGEST", error.to_string()))) + .collect::>>()?; + members.sort_by_key(|entry| entry.path().strip_prefix(tree).unwrap().to_path_buf()); + for entry in members { + if !entry.file_type().is_file() { + continue; + } + let relative = entry + .path() + .strip_prefix(tree) + .unwrap() + .to_string_lossy() + .replace('\\', "/"); + let label = normalized_relative(&format!("{prefix}/{relative}"), "source tree member")?; + digest.update(label.as_bytes()); + digest.update([0]); + digest.update( + fs::read(entry.path()) + .map_err(|error| fail("BUCK2_TS_DIGEST", error.to_string()))?, + ); + } + } + Ok(format!( + "sha256:{}", + digest + .finalize() + .iter() + .map(|byte| format!("{byte:02x}")) + .collect::() + )) +} + +fn bundle(args: BundleArgs) -> ToolResult<()> { + require_executable(&args.bun, "bun")?; + require_executable(&args.patchelf, "patchelf")?; + safe_text(&args.target, "target")?; + let entry = normalized_relative(&args.entry, "entry")?; + let binary_name = normalized_relative(&args.binary_name, "binary name")?; + if binary_name.contains('/') { + return Err(fail( + "BUCK2_TS_NAME", + "binary name must be one path component", + )); + } + let temp = tempdir().map_err(|error| fail("BUCK2_TS_TEMP", error.to_string()))?; + let workspace = temp.path().join("workspace"); + fs::create_dir(&workspace).map_err(|error| fail("BUCK2_TS_TEMP", error.to_string()))?; + stage(&args.common, &workspace)?; + let staged_entry = workspace.join(&entry); + if !staged_entry.is_file() { + return Err(fail( + "BUCK2_TS_ENTRY", + "entry is absent from the declared source graph", + )); + } + let stable = temp.path().join("out").join(&binary_name); + fs::create_dir_all(stable.parent().unwrap()) + .map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + let stable_text = stable + .to_str() + .ok_or_else(|| fail("BUCK2_TS_PATH", "temporary output path is not UTF-8"))?; + let entry_text = staged_entry + .to_str() + .ok_or_else(|| fail("BUCK2_TS_PATH", "entry path is not UTF-8"))?; + run_tool( + &args.bun, + &["build", entry_text, "--compile", "--outfile", stable_text], + &workspace, + &temp.path().join("home"), + )?; + if let Some(parent) = args.output.parent() { + fs::create_dir_all(parent).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + } + fs::copy(&stable, &args.output).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + let output_text = args + .output + .to_str() + .ok_or_else(|| fail("BUCK2_TS_PATH", "output path is not UTF-8"))?; + run_tool( + &args.patchelf, + &[ + "--set-interpreter", + "/lib64/ld-linux-x86-64.so.2", + "--remove-rpath", + output_text, + ], + temp.path(), + &temp.path().join("home"), + )?; + fs::set_permissions(&args.output, fs::Permissions::from_mode(0o555)) + .map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + let binary = + fs::read(&args.output).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + if let Some(parent) = args.archive.parent() { + fs::create_dir_all(parent).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + } + let file = + fs::File::create(&args.archive).map_err(|error| fail("BUCK2_TS_TAR", error.to_string()))?; + let mut builder = Builder::new(file); + append_tar(&mut builder, "bin", None, 0o555)?; + append_tar( + &mut builder, + &format!("bin/{binary_name}"), + Some(&binary), + 0o555, + )?; + builder + .finish() + .map_err(|error| fail("BUCK2_TS_TAR", error.to_string()))?; + drop(builder); + let payload_hex = sha256_file(&args.archive)?; + let payload_bytes = (0..payload_hex.len()) + .step_by(2) + .map(|index| u8::from_str_radix(&payload_hex[index..index + 2], 16).unwrap()) + .collect::>(); + let descriptor = json!({ + "entrypoints":[format!("bin/{binary_name}")], "name":binary_name, + "payload":{"digest":{"algorithm":"sha256","sri":format!("sha256-{}", STANDARD.encode(payload_bytes))},"file":"artifact.tar","format":"tar","sizeBytes":fs::metadata(&args.archive).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?.len()}, + "platform":{"abi":"glibc","architecture":"x86_64","os":"linux"}, + "runtime":{ + "elfClass":"ELF64", + "inspectionContract":"elf-dynamic/v1", + "interpreter":"/lib64/ld-linux-x86-64.so.2", + "kind":"elf-dynamic", + "machine":"x86_64", + "neededLibraries":["ld-linux-x86-64.so.2","libc.so.6","libdl.so.2","libm.so.6","libpthread.so.0"], + "rpathPolicy":"empty/v1", + "symbolVersionFloors":["GLIBC_2.10","GLIBC_2.12","GLIBC_2.14","GLIBC_2.16","GLIBC_2.17","GLIBC_2.2.5","GLIBC_2.3","GLIBC_2.3.2","GLIBC_2.3.4","GLIBC_2.4","GLIBC_2.6","GLIBC_2.7","GLIBC_2.8","GLIBC_2.9"] + }, + "schema":"buck-build-product/v1", + "semanticProvenance":{"recipe":input_digest(&args)?,"target":args.target,"toolchain":format!("bun:{};patchelf:{}", args.bun.display(), args.patchelf.display())}, + }); + if let Some(parent) = args.descriptor.parent() { + fs::create_dir_all(parent).map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string()))?; + } + fs::write(args.descriptor, canonical_json(&descriptor)?) + .map_err(|error| fail("BUCK2_TS_OUTPUT", error.to_string())) +} + +fn main() { + let result = match Cli::parse().command { + CommandKind::Check(args) => check(args), + CommandKind::Bundle(args) => bundle(args), + }; + if let Err(error) = result { + eprintln!("{error}"); + std::process::exit(1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn source_edges_reject_duplicate_destinations_before_tool_execution() { + let temporary = tempdir().unwrap(); + let dependency_root = temporary.path().join("deps"); + fs::create_dir_all(dependency_root.join("node_modules")).unwrap(); + let first = temporary.path().join("first.ts"); + let second = temporary.path().join("second.ts"); + fs::write(&first, "export const first = 1\n").unwrap(); + fs::write(&second, "export const second = 2\n").unwrap(); + let common = CommonArgs { + dependency_root, + native_packages: vec![], + source_labels: vec!["pkg/mod.ts".into(), "pkg/mod.ts".into()], + sources: vec![first, second], + source_tree_prefixes: vec![], + source_trees: vec![], + }; + let workspace = temporary.path().join("workspace"); + fs::create_dir(&workspace).unwrap(); + let error = stage(&common, &workspace).unwrap_err(); + assert_eq!(error.code, "BUCK2_TS_DUPLICATE"); + } + + #[test] + fn deterministic_tar_header_does_not_encode_host_metadata() { + let temporary = tempdir().unwrap(); + let archive = temporary.path().join("artifact.tar"); + let file = fs::File::create(&archive).unwrap(); + let mut builder = Builder::new(file); + append_tar(&mut builder, "bin", None, 0o555).unwrap(); + append_tar(&mut builder, "bin/tool", Some(b"payload"), 0o555).unwrap(); + builder.finish().unwrap(); + drop(builder); + let first = fs::read(&archive).unwrap(); + + let file = fs::File::create(&archive).unwrap(); + let mut builder = Builder::new(file); + append_tar(&mut builder, "bin", None, 0o555).unwrap(); + append_tar(&mut builder, "bin/tool", Some(b"payload"), 0o555).unwrap(); + builder.finish().unwrap(); + drop(builder); + assert_eq!(first, fs::read(&archive).unwrap()); + } + + #[test] + fn dependency_symlink_must_stay_inside_declared_closure() { + let temporary = tempdir().unwrap(); + let closure = temporary.path().join("closure"); + let modules = closure.join("node_modules"); + fs::create_dir_all(&modules).unwrap(); + let external = temporary.path().join("external"); + fs::create_dir(&external).unwrap(); + symlink(&external, modules.join("escape")).unwrap(); + let output = temporary.path().join("output"); + let error = copy_tree(&modules, &output, &closure).unwrap_err(); + assert_eq!(error.code, "BUCK2_TS_DEPENDENCY_SYMLINK"); + } +} diff --git a/rust/reindeer.bzl b/rust/reindeer.bzl new file mode 100644 index 000000000..0cd9fcc42 --- /dev/null +++ b/rust/reindeer.bzl @@ -0,0 +1,11 @@ +"""Hermetic execution wrapper for reviewed Reindeer build scripts.""" + +load("@prelude//rust:cargo_buildscript.bzl", _buildscript_run = "buildscript_run") + +def reindeer_buildscript_run(name, env = {}, **kwargs): + configured = read_root_config("rust_toolchain", "tool_path", "") + if not configured or not configured.startswith("/nix/store/") or ":/nix/store/" not in configured: + fail("rust_toolchain.tool_path must contain exact Nix store tool roots") + buildscript_env = dict(env) + buildscript_env["PATH"] = configured + _buildscript_run(name = name, env = buildscript_env, **kwargs) diff --git a/rust/reindeer.toml b/rust/reindeer.toml new file mode 100644 index 000000000..88323a88b --- /dev/null +++ b/rust/reindeer.toml @@ -0,0 +1,33 @@ +manifest_path = "Cargo.toml" +third_party_dir = "third-party" +precise_srcs = true +include_top_level = false +unresolved_fixup_error = true +cargo_env = false +vendor = false + +[platform.x86_64-linux] +target = "x86_64-unknown-linux-gnu" +execution-platform = true + +[platform.x86_64-linux-musl] +target = "x86_64-unknown-linux-musl" +execution-platform = false + +[buck] +file_name = "BUCK" +split = false +rust_library = "cargo.rust_library" +rust_binary = "cargo.rust_binary" +generated_file_header = """ +## +## GENERATED FILE - DO NOT EDIT. Generated by Reindeer 2026.05.04.00. +## Sources: rust/Cargo.toml, rust/Cargo.lock, rust/reindeer.toml, rust/third-party/fixups/** +## Regenerate: devenv tasks run buck2:rust-deps:generate +## +""" +buckfile_imports = """ +load("@prelude//rust:cargo_package.bzl", "cargo") +load("//rust:reindeer.bzl", "reindeer_buildscript_run") +""" +buildscript_genrule = "reindeer_buildscript_run" diff --git a/rust/third-party/BUCK b/rust/third-party/BUCK new file mode 100644 index 000000000..9aaff262f --- /dev/null +++ b/rust/third-party/BUCK @@ -0,0 +1,3507 @@ +## +## GENERATED FILE - DO NOT EDIT. Generated by Reindeer 2026.05.04.00. +## Sources: rust/Cargo.toml, rust/Cargo.lock, rust/reindeer.toml, rust/third-party/fixups/** +## Regenerate: devenv tasks run buck2:rust-deps:generate +## + +load("@prelude//rust:cargo_package.bzl", "cargo") +load("//rust:reindeer.bzl", "reindeer_buildscript_run") + +http_archive( + name = "anstream-1.0.0.crate", + sha256 = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d", + strip_prefix = "anstream-1.0.0", + urls = ["https://static.crates.io/crates/anstream/1.0.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "anstream-1", + srcs = [":anstream-1.0.0.crate"], + crate = "anstream", + crate_root = "anstream-1.0.0.crate/src/lib.rs", + edition = "2021", + features = [ + "auto", + "default", + "wincon", + ], + visibility = [], + deps = [ + ":anstyle-1", + ":anstyle-parse-1", + ":anstyle-query-1", + ":colorchoice-1", + ":is_terminal_polyfill-1", + ":utf8parse-0.2", + ], +) + +http_archive( + name = "anstyle-1.0.14.crate", + sha256 = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000", + strip_prefix = "anstyle-1.0.14", + urls = ["https://static.crates.io/crates/anstyle/1.0.14/download"], + visibility = [], +) + +cargo.rust_library( + name = "anstyle-1", + srcs = [":anstyle-1.0.14.crate"], + crate = "anstyle", + crate_root = "anstyle-1.0.14.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "anstyle-parse-1.0.0.crate", + sha256 = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e", + strip_prefix = "anstyle-parse-1.0.0", + urls = ["https://static.crates.io/crates/anstyle-parse/1.0.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "anstyle-parse-1", + srcs = [":anstyle-parse-1.0.0.crate"], + crate = "anstyle_parse", + crate_root = "anstyle-parse-1.0.0.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "utf8", + ], + visibility = [], + deps = [":utf8parse-0.2"], +) + +http_archive( + name = "anstyle-query-1.1.5.crate", + sha256 = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc", + strip_prefix = "anstyle-query-1.1.5", + urls = ["https://static.crates.io/crates/anstyle-query/1.1.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "anstyle-query-1", + srcs = [":anstyle-query-1.1.5.crate"], + crate = "anstyle_query", + crate_root = "anstyle-query-1.1.5.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "anyhow-1.0.104.crate", + sha256 = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470", + strip_prefix = "anyhow-1.0.104", + urls = ["https://static.crates.io/crates/anyhow/1.0.104/download"], + visibility = [], +) + +cargo.rust_library( + name = "anyhow-1", + srcs = [":anyhow-1.0.104.crate"], + crate = "anyhow", + crate_root = "anyhow-1.0.104.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :anyhow-1-build-script-run[out_dir])", + }, + features = [ + "default", + "std", + ], + rustc_flags = ["@$(location :anyhow-1-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "anyhow-1-build-script-build", + srcs = [":anyhow-1.0.104.crate"], + crate = "build_script_build", + crate_root = "anyhow-1.0.104.crate/build.rs", + edition = "2021", + features = [ + "default", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "anyhow-1-build-script-run", + package_name = "anyhow", + buildscript_rule = ":anyhow-1-build-script-build", + features = [ + "default", + "std", + ], + version = "1.0.104", +) + +http_archive( + name = "async-stream-0.3.6.crate", + sha256 = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476", + strip_prefix = "async-stream-0.3.6", + urls = ["https://static.crates.io/crates/async-stream/0.3.6/download"], + visibility = [], +) + +cargo.rust_library( + name = "async-stream-0.3", + srcs = [":async-stream-0.3.6.crate"], + crate = "async_stream", + crate_root = "async-stream-0.3.6.crate/src/lib.rs", + edition = "2021", + visibility = [], + deps = [ + ":async-stream-impl-0.3", + ":futures-core-0.3", + ":pin-project-lite-0.2", + ], +) + +http_archive( + name = "async-stream-impl-0.3.6.crate", + sha256 = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d", + strip_prefix = "async-stream-impl-0.3.6", + urls = ["https://static.crates.io/crates/async-stream-impl/0.3.6/download"], + visibility = [], +) + +cargo.rust_library( + name = "async-stream-impl-0.3", + srcs = [":async-stream-impl-0.3.6.crate"], + crate = "async_stream_impl", + crate_root = "async-stream-impl-0.3.6.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "async-trait-0.1.91.crate", + sha256 = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec", + strip_prefix = "async-trait-0.1.91", + urls = ["https://static.crates.io/crates/async-trait/0.1.91/download"], + visibility = [], +) + +cargo.rust_library( + name = "async-trait-0.1", + srcs = [":async-trait-0.1.91.crate"], + crate = "async_trait", + crate_root = "async-trait-0.1.91.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-3", + ], +) + +http_archive( + name = "atomic-waker-1.1.2.crate", + sha256 = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0", + strip_prefix = "atomic-waker-1.1.2", + urls = ["https://static.crates.io/crates/atomic-waker/1.1.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "atomic-waker-1", + srcs = [":atomic-waker-1.1.2.crate"], + crate = "atomic_waker", + crate_root = "atomic-waker-1.1.2.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +http_archive( + name = "autocfg-1.5.1.crate", + sha256 = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53", + strip_prefix = "autocfg-1.5.1", + urls = ["https://static.crates.io/crates/autocfg/1.5.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "autocfg-1", + srcs = [":autocfg-1.5.1.crate"], + crate = "autocfg", + crate_root = "autocfg-1.5.1.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +alias( + name = "axum", + actual = ":axum-0.7", + visibility = ["PUBLIC"], +) + +http_archive( + name = "axum-0.7.9.crate", + sha256 = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f", + strip_prefix = "axum-0.7.9", + urls = ["https://static.crates.io/crates/axum/0.7.9/download"], + visibility = [], +) + +cargo.rust_library( + name = "axum-0.7", + srcs = [":axum-0.7.9.crate"], + crate = "axum", + crate_root = "axum-0.7.9.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "form", + "http1", + "json", + "matched-path", + "original-uri", + "query", + "tokio", + "tower-log", + "tracing", + ], + visibility = [], + deps = [ + ":async-trait-0.1", + ":axum-core-0.4", + ":bytes-1", + ":futures-util-0.3", + ":http-1", + ":http-body-1", + ":http-body-util-0.1", + ":hyper-1", + ":hyper-util-0.1", + ":itoa-1", + ":matchit-0.7", + ":memchr-2", + ":mime-0.3", + ":percent-encoding-2", + ":pin-project-lite-0.2", + ":rustversion-1", + ":serde-1", + ":serde_json-1", + ":serde_path_to_error-0.1", + ":serde_urlencoded-0.7", + ":sync_wrapper-1", + ":tokio-1", + ":tower-0.5", + ":tower-layer-0.3", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +http_archive( + name = "axum-core-0.4.5.crate", + sha256 = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199", + strip_prefix = "axum-core-0.4.5", + urls = ["https://static.crates.io/crates/axum-core/0.4.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "axum-core-0.4", + srcs = [":axum-core-0.4.5.crate"], + crate = "axum_core", + crate_root = "axum-core-0.4.5.crate/src/lib.rs", + edition = "2021", + features = ["tracing"], + visibility = [], + deps = [ + ":async-trait-0.1", + ":bytes-1", + ":futures-util-0.3", + ":http-1", + ":http-body-1", + ":http-body-util-0.1", + ":mime-0.3", + ":pin-project-lite-0.2", + ":rustversion-1", + ":sync_wrapper-1", + ":tower-layer-0.3", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +alias( + name = "base64", + actual = ":base64-0.22", + visibility = ["PUBLIC"], +) + +http_archive( + name = "base64-0.22.1.crate", + sha256 = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + strip_prefix = "base64-0.22.1", + urls = ["https://static.crates.io/crates/base64/0.22.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "base64-0.22", + srcs = [":base64-0.22.1.crate"], + crate = "base64", + crate_root = "base64-0.22.1.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "bitflags-2.13.1.crate", + sha256 = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da", + strip_prefix = "bitflags-2.13.1", + urls = ["https://static.crates.io/crates/bitflags/2.13.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "bitflags-2", + srcs = [":bitflags-2.13.1.crate"], + crate = "bitflags", + crate_root = "bitflags-2.13.1.crate/src/lib.rs", + edition = "2021", + features = ["std"], + visibility = [], +) + +http_archive( + name = "block-buffer-0.12.1.crate", + sha256 = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa", + strip_prefix = "block-buffer-0.12.1", + urls = ["https://static.crates.io/crates/block-buffer/0.12.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "block-buffer-0.12", + srcs = [":block-buffer-0.12.1.crate"], + crate = "block_buffer", + crate_root = "block-buffer-0.12.1.crate/src/lib.rs", + edition = "2024", + visibility = [], + deps = [":hybrid-array-0.4"], +) + +http_archive( + name = "bytes-1.12.1.crate", + sha256 = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04", + strip_prefix = "bytes-1.12.1", + urls = ["https://static.crates.io/crates/bytes/1.12.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "bytes-1", + srcs = [":bytes-1.12.1.crate"], + crate = "bytes", + crate_root = "bytes-1.12.1.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "cfg-if-1.0.4.crate", + sha256 = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801", + strip_prefix = "cfg-if-1.0.4", + urls = ["https://static.crates.io/crates/cfg-if/1.0.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "cfg-if-1", + srcs = [":cfg-if-1.0.4.crate"], + crate = "cfg_if", + crate_root = "cfg-if-1.0.4.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +alias( + name = "clap", + actual = ":clap-4", + visibility = ["PUBLIC"], +) + +http_archive( + name = "clap-4.6.6.crate", + sha256 = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca", + strip_prefix = "clap-4.6.6", + urls = ["https://static.crates.io/crates/clap/4.6.6/download"], + visibility = [], +) + +cargo.rust_library( + name = "clap-4", + srcs = [":clap-4.6.6.crate"], + crate = "clap", + crate_root = "clap-4.6.6.crate/src/lib.rs", + edition = "2024", + features = [ + "color", + "default", + "derive", + "error-context", + "help", + "std", + "suggestions", + "usage", + ], + visibility = [], + deps = [ + ":clap_builder-4", + ":clap_derive-4", + ], +) + +http_archive( + name = "clap_builder-4.6.6.crate", + sha256 = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889", + strip_prefix = "clap_builder-4.6.6", + urls = ["https://static.crates.io/crates/clap_builder/4.6.6/download"], + visibility = [], +) + +cargo.rust_library( + name = "clap_builder-4", + srcs = [":clap_builder-4.6.6.crate"], + crate = "clap_builder", + crate_root = "clap_builder-4.6.6.crate/src/lib.rs", + edition = "2024", + features = [ + "color", + "error-context", + "help", + "std", + "suggestions", + "usage", + ], + visibility = [], + deps = [ + ":anstream-1", + ":anstyle-1", + ":clap_lex-1", + ":strsim-0.11", + ], +) + +http_archive( + name = "clap_derive-4.6.4.crate", + sha256 = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061", + strip_prefix = "clap_derive-4.6.4", + urls = ["https://static.crates.io/crates/clap_derive/4.6.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "clap_derive-4", + srcs = [":clap_derive-4.6.4.crate"], + crate = "clap_derive", + crate_root = "clap_derive-4.6.4.crate/src/lib.rs", + edition = "2024", + features = ["default"], + proc_macro = True, + visibility = [], + deps = [ + ":heck-0.5", + ":proc-macro2-1", + ":quote-1", + ":syn-3", + ], +) + +http_archive( + name = "clap_lex-1.1.0.crate", + sha256 = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9", + strip_prefix = "clap_lex-1.1.0", + urls = ["https://static.crates.io/crates/clap_lex/1.1.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "clap_lex-1", + srcs = [":clap_lex-1.1.0.crate"], + crate = "clap_lex", + crate_root = "clap_lex-1.1.0.crate/src/lib.rs", + edition = "2024", + visibility = [], +) + +http_archive( + name = "colorchoice-1.0.5.crate", + sha256 = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570", + strip_prefix = "colorchoice-1.0.5", + urls = ["https://static.crates.io/crates/colorchoice/1.0.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "colorchoice-1", + srcs = [":colorchoice-1.0.5.crate"], + crate = "colorchoice", + crate_root = "colorchoice-1.0.5.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "const-oid-0.10.2.crate", + sha256 = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c", + strip_prefix = "const-oid-0.10.2", + urls = ["https://static.crates.io/crates/const-oid/0.10.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "const-oid-0.10", + srcs = [":const-oid-0.10.2.crate"], + crate = "const_oid", + crate_root = "const-oid-0.10.2.crate/src/lib.rs", + edition = "2024", + visibility = [], +) + +http_archive( + name = "cpufeatures-0.3.0.crate", + sha256 = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201", + strip_prefix = "cpufeatures-0.3.0", + urls = ["https://static.crates.io/crates/cpufeatures/0.3.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "cpufeatures-0.3", + srcs = [":cpufeatures-0.3.0.crate"], + crate = "cpufeatures", + crate_root = "cpufeatures-0.3.0.crate/src/lib.rs", + edition = "2024", + visibility = [], +) + +http_archive( + name = "crypto-common-0.2.2.crate", + sha256 = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453", + strip_prefix = "crypto-common-0.2.2", + urls = ["https://static.crates.io/crates/crypto-common/0.2.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "crypto-common-0.2", + srcs = [":crypto-common-0.2.2.crate"], + crate = "crypto_common", + crate_root = "crypto-common-0.2.2.crate/src/lib.rs", + edition = "2024", + visibility = [], + deps = [":hybrid-array-0.4"], +) + +http_archive( + name = "digest-0.11.3.crate", + sha256 = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2", + strip_prefix = "digest-0.11.3", + urls = ["https://static.crates.io/crates/digest/0.11.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "digest-0.11", + srcs = [":digest-0.11.3.crate"], + crate = "digest", + crate_root = "digest-0.11.3.crate/src/lib.rs", + edition = "2024", + features = [ + "alloc", + "block-api", + "default", + "oid", + ], + named_deps = { + "common": ":crypto-common-0.2", + }, + visibility = [], + deps = [ + ":block-buffer-0.12", + ":const-oid-0.10", + ], +) + +http_archive( + name = "either-1.17.0.crate", + sha256 = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d", + strip_prefix = "either-1.17.0", + urls = ["https://static.crates.io/crates/either/1.17.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "either-1", + srcs = [":either-1.17.0.crate"], + crate = "either", + crate_root = "either-1.17.0.crate/src/lib.rs", + edition = "2021", + features = [ + "std", + "use_std", + ], + visibility = [], +) + +http_archive( + name = "equivalent-1.0.2.crate", + sha256 = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + strip_prefix = "equivalent-1.0.2", + urls = ["https://static.crates.io/crates/equivalent/1.0.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "equivalent-1", + srcs = [":equivalent-1.0.2.crate"], + crate = "equivalent", + crate_root = "equivalent-1.0.2.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +http_archive( + name = "errno-0.3.14.crate", + sha256 = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + strip_prefix = "errno-0.3.14", + urls = ["https://static.crates.io/crates/errno/0.3.14/download"], + visibility = [], +) + +cargo.rust_library( + name = "errno-0.3", + srcs = [":errno-0.3.14.crate"], + crate = "errno", + crate_root = "errno-0.3.14.crate/src/lib.rs", + edition = "2018", + features = [ + "default", + "std", + ], + visibility = [], + deps = [":libc-0.2"], +) + +http_archive( + name = "fastrand-2.5.0.crate", + sha256 = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223", + strip_prefix = "fastrand-2.5.0", + urls = ["https://static.crates.io/crates/fastrand/2.5.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "fastrand-2", + srcs = [":fastrand-2.5.0.crate"], + crate = "fastrand", + crate_root = "fastrand-2.5.0.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "filetime-0.2.29.crate", + sha256 = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759", + strip_prefix = "filetime-0.2.29", + urls = ["https://static.crates.io/crates/filetime/0.2.29/download"], + visibility = [], +) + +cargo.rust_library( + name = "filetime-0.2", + srcs = [":filetime-0.2.29.crate"], + crate = "filetime", + crate_root = "filetime-0.2.29.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [ + ":cfg-if-1", + ":libc-0.2", + ], +) + +http_archive( + name = "fnv-1.0.7.crate", + sha256 = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + strip_prefix = "fnv-1.0.7", + urls = ["https://static.crates.io/crates/fnv/1.0.7/download"], + visibility = [], +) + +cargo.rust_library( + name = "fnv-1", + srcs = [":fnv-1.0.7.crate"], + crate = "fnv", + crate_root = "fnv-1.0.7.crate/lib.rs", + edition = "2015", + features = [ + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "form_urlencoded-1.2.2.crate", + sha256 = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf", + strip_prefix = "form_urlencoded-1.2.2", + urls = ["https://static.crates.io/crates/form_urlencoded/1.2.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "form_urlencoded-1", + srcs = [":form_urlencoded-1.2.2.crate"], + crate = "form_urlencoded", + crate_root = "form_urlencoded-1.2.2.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], + deps = [":percent-encoding-2"], +) + +http_archive( + name = "futures-channel-0.3.33.crate", + sha256 = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae", + strip_prefix = "futures-channel-0.3.33", + urls = ["https://static.crates.io/crates/futures-channel/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-channel-0.3", + srcs = [":futures-channel-0.3.33.crate"], + crate = "futures_channel", + crate_root = "futures-channel-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], + deps = [":futures-core-0.3"], +) + +http_archive( + name = "futures-core-0.3.33.crate", + sha256 = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7", + strip_prefix = "futures-core-0.3.33", + urls = ["https://static.crates.io/crates/futures-core/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-core-0.3", + srcs = [":futures-core-0.3.33.crate"], + crate = "futures_core", + crate_root = "futures-core-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "futures-executor-0.3.33.crate", + sha256 = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458", + strip_prefix = "futures-executor-0.3.33", + urls = ["https://static.crates.io/crates/futures-executor/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-executor-0.3", + srcs = [":futures-executor-0.3.33.crate"], + crate = "futures_executor", + crate_root = "futures-executor-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "default", + "std", + ], + visibility = [], + deps = [ + ":futures-core-0.3", + ":futures-task-0.3", + ":futures-util-0.3", + ], +) + +http_archive( + name = "futures-macro-0.3.33.crate", + sha256 = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b", + strip_prefix = "futures-macro-0.3.33", + urls = ["https://static.crates.io/crates/futures-macro/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-macro-0.3", + srcs = [":futures-macro-0.3.33.crate"], + crate = "futures_macro", + crate_root = "futures-macro-0.3.33.crate/src/lib.rs", + edition = "2018", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "futures-sink-0.3.33.crate", + sha256 = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307", + strip_prefix = "futures-sink-0.3.33", + urls = ["https://static.crates.io/crates/futures-sink/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-sink-0.3", + srcs = [":futures-sink-0.3.33.crate"], + crate = "futures_sink", + crate_root = "futures-sink-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "futures-task-0.3.33.crate", + sha256 = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109", + strip_prefix = "futures-task-0.3.33", + urls = ["https://static.crates.io/crates/futures-task/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-task-0.3", + srcs = [":futures-task-0.3.33.crate"], + crate = "futures_task", + crate_root = "futures-task-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "std", + ], + visibility = [], +) + +http_archive( + name = "futures-util-0.3.33.crate", + sha256 = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa", + strip_prefix = "futures-util-0.3.33", + urls = ["https://static.crates.io/crates/futures-util/0.3.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "futures-util-0.3", + srcs = [":futures-util-0.3.33.crate"], + crate = "futures_util", + crate_root = "futures-util-0.3.33.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "async-await", + "async-await-macro", + "futures-macro", + "futures-sink", + "sink", + "slab", + "std", + ], + visibility = [], + deps = [ + ":futures-core-0.3", + ":futures-macro-0.3", + ":futures-sink-0.3", + ":futures-task-0.3", + ":pin-project-lite-0.2", + ":slab-0.4", + ], +) + +http_archive( + name = "getrandom-0.2.17.crate", + sha256 = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0", + strip_prefix = "getrandom-0.2.17", + urls = ["https://static.crates.io/crates/getrandom/0.2.17/download"], + visibility = [], +) + +cargo.rust_library( + name = "getrandom-0.2", + srcs = [":getrandom-0.2.17.crate"], + crate = "getrandom", + crate_root = "getrandom-0.2.17.crate/src/lib.rs", + edition = "2018", + features = ["std"], + visibility = [], + deps = [ + ":cfg-if-1", + ":libc-0.2", + ], +) + +alias( + name = "getrandom", + actual = ":getrandom-0.4", + visibility = ["PUBLIC"], +) + +http_archive( + name = "getrandom-0.4.3.crate", + sha256 = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099", + strip_prefix = "getrandom-0.4.3", + urls = ["https://static.crates.io/crates/getrandom/0.4.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "getrandom-0.4", + srcs = [":getrandom-0.4.3.crate"], + crate = "getrandom", + crate_root = "getrandom-0.4.3.crate/src/lib.rs", + edition = "2024", + env = { + "OUT_DIR": "$(location :getrandom-0.4-build-script-run[out_dir])", + }, + rustc_flags = ["@$(location :getrandom-0.4-build-script-run[rustc_flags])"], + visibility = [], + deps = [ + ":cfg-if-1", + ":libc-0.2", + ], +) + +cargo.rust_binary( + name = "getrandom-0.4-build-script-build", + srcs = [":getrandom-0.4.3.crate"], + crate = "build_script_build", + crate_root = "getrandom-0.4.3.crate/build.rs", + edition = "2024", + visibility = [], +) + +reindeer_buildscript_run( + name = "getrandom-0.4-build-script-run", + package_name = "getrandom", + buildscript_rule = ":getrandom-0.4-build-script-build", + version = "0.4.3", +) + +http_archive( + name = "glob-0.3.3.crate", + sha256 = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280", + strip_prefix = "glob-0.3.3", + urls = ["https://static.crates.io/crates/glob/0.3.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "glob-0.3", + srcs = [":glob-0.3.3.crate"], + crate = "glob", + crate_root = "glob-0.3.3.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +http_archive( + name = "h2-0.4.15.crate", + sha256 = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155", + strip_prefix = "h2-0.4.15", + urls = ["https://static.crates.io/crates/h2/0.4.15/download"], + visibility = [], +) + +cargo.rust_library( + name = "h2-0.4", + srcs = [":h2-0.4.15.crate"], + crate = "h2", + crate_root = "h2-0.4.15.crate/src/lib.rs", + edition = "2021", + visibility = [], + deps = [ + ":atomic-waker-1", + ":bytes-1", + ":fnv-1", + ":futures-core-0.3", + ":futures-sink-0.3", + ":http-1", + ":indexmap-2", + ":slab-0.4", + ":tokio-1", + ":tokio-util-0.7", + ":tracing-0.1", + ], +) + +http_archive( + name = "hashbrown-0.12.3.crate", + sha256 = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888", + strip_prefix = "hashbrown-0.12.3", + urls = ["https://static.crates.io/crates/hashbrown/0.12.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "hashbrown-0.12", + srcs = [":hashbrown-0.12.3.crate"], + crate = "hashbrown", + crate_root = "hashbrown-0.12.3.crate/src/lib.rs", + edition = "2021", + features = ["raw"], + visibility = [], +) + +http_archive( + name = "hashbrown-0.17.1.crate", + sha256 = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a", + strip_prefix = "hashbrown-0.17.1", + urls = ["https://static.crates.io/crates/hashbrown/0.17.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "hashbrown-0.17", + srcs = [":hashbrown-0.17.1.crate"], + crate = "hashbrown", + crate_root = "hashbrown-0.17.1.crate/src/lib.rs", + edition = "2024", + visibility = [], +) + +http_archive( + name = "heck-0.5.0.crate", + sha256 = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea", + strip_prefix = "heck-0.5.0", + urls = ["https://static.crates.io/crates/heck/0.5.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "heck-0.5", + srcs = [":heck-0.5.0.crate"], + crate = "heck", + crate_root = "heck-0.5.0.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "hex-0.4.3.crate", + sha256 = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + strip_prefix = "hex-0.4.3", + urls = ["https://static.crates.io/crates/hex/0.4.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "hex-0.4", + srcs = [":hex-0.4.3.crate"], + crate = "hex", + crate_root = "hex-0.4.3.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "http-1.5.0.crate", + sha256 = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0", + strip_prefix = "http-1.5.0", + urls = ["https://static.crates.io/crates/http/1.5.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "http-1", + srcs = [":http-1.5.0.crate"], + crate = "http", + crate_root = "http-1.5.0.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "std", + ], + visibility = [], + deps = [ + ":bytes-1", + ":itoa-1", + ], +) + +http_archive( + name = "http-body-1.1.0.crate", + sha256 = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c", + strip_prefix = "http-body-1.1.0", + urls = ["https://static.crates.io/crates/http-body/1.1.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "http-body-1", + srcs = [":http-body-1.1.0.crate"], + crate = "http_body", + crate_root = "http-body-1.1.0.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [ + ":bytes-1", + ":http-1", + ], +) + +http_archive( + name = "http-body-util-0.1.4.crate", + sha256 = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2", + strip_prefix = "http-body-util-0.1.4", + urls = ["https://static.crates.io/crates/http-body-util/0.1.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "http-body-util-0.1", + srcs = [":http-body-util-0.1.4.crate"], + crate = "http_body_util", + crate_root = "http-body-util-0.1.4.crate/src/lib.rs", + edition = "2018", + features = ["default"], + visibility = [], + deps = [ + ":bytes-1", + ":futures-core-0.3", + ":http-1", + ":http-body-1", + ":pin-project-lite-0.2", + ], +) + +http_archive( + name = "httparse-1.10.1.crate", + sha256 = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87", + strip_prefix = "httparse-1.10.1", + urls = ["https://static.crates.io/crates/httparse/1.10.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "httparse-1", + srcs = [":httparse-1.10.1.crate"], + crate = "httparse", + crate_root = "httparse-1.10.1.crate/src/lib.rs", + edition = "2018", + env = { + "OUT_DIR": "$(location :httparse-1-build-script-run[out_dir])", + }, + features = [ + "default", + "std", + ], + rustc_flags = ["@$(location :httparse-1-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "httparse-1-build-script-build", + srcs = [":httparse-1.10.1.crate"], + crate = "build_script_build", + crate_root = "httparse-1.10.1.crate/build.rs", + edition = "2018", + features = [ + "default", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "httparse-1-build-script-run", + package_name = "httparse", + buildscript_rule = ":httparse-1-build-script-build", + features = [ + "default", + "std", + ], + version = "1.10.1", +) + +http_archive( + name = "httpdate-1.0.3.crate", + sha256 = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9", + strip_prefix = "httpdate-1.0.3", + urls = ["https://static.crates.io/crates/httpdate/1.0.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "httpdate-1", + srcs = [":httpdate-1.0.3.crate"], + crate = "httpdate", + crate_root = "httpdate-1.0.3.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "hybrid-array-0.4.14.crate", + sha256 = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b", + strip_prefix = "hybrid-array-0.4.14", + urls = ["https://static.crates.io/crates/hybrid-array/0.4.14/download"], + visibility = [], +) + +cargo.rust_library( + name = "hybrid-array-0.4", + srcs = [":hybrid-array-0.4.14.crate"], + crate = "hybrid_array", + crate_root = "hybrid-array-0.4.14.crate/src/lib.rs", + edition = "2024", + visibility = [], + deps = [":typenum-1"], +) + +http_archive( + name = "hyper-1.11.0.crate", + sha256 = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72", + strip_prefix = "hyper-1.11.0", + urls = ["https://static.crates.io/crates/hyper/1.11.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "hyper-1", + srcs = [":hyper-1.11.0.crate"], + crate = "hyper", + crate_root = "hyper-1.11.0.crate/src/lib.rs", + edition = "2021", + features = [ + "client", + "default", + "http1", + "http2", + "server", + ], + visibility = [], + deps = [ + ":atomic-waker-1", + ":bytes-1", + ":futures-channel-0.3", + ":futures-core-0.3", + ":h2-0.4", + ":http-1", + ":http-body-1", + ":httparse-1", + ":httpdate-1", + ":itoa-1", + ":pin-project-lite-0.2", + ":smallvec-1", + ":tokio-1", + ":want-0.3", + ], +) + +http_archive( + name = "hyper-timeout-0.5.2.crate", + sha256 = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0", + strip_prefix = "hyper-timeout-0.5.2", + urls = ["https://static.crates.io/crates/hyper-timeout/0.5.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "hyper-timeout-0.5", + srcs = [":hyper-timeout-0.5.2.crate"], + crate = "hyper_timeout", + crate_root = "hyper-timeout-0.5.2.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [ + ":hyper-1", + ":hyper-util-0.1", + ":pin-project-lite-0.2", + ":tokio-1", + ":tower-service-0.3", + ], +) + +http_archive( + name = "hyper-util-0.1.20.crate", + sha256 = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0", + strip_prefix = "hyper-util-0.1.20", + urls = ["https://static.crates.io/crates/hyper-util/0.1.20/download"], + visibility = [], +) + +cargo.rust_library( + name = "hyper-util-0.1", + srcs = [":hyper-util-0.1.20.crate"], + crate = "hyper_util", + crate_root = "hyper-util-0.1.20.crate/src/lib.rs", + edition = "2021", + features = [ + "client", + "client-legacy", + "default", + "http1", + "http2", + "server", + "server-auto", + "service", + "tokio", + ], + visibility = [], + deps = [ + ":bytes-1", + ":futures-channel-0.3", + ":futures-util-0.3", + ":http-1", + ":http-body-1", + ":hyper-1", + ":libc-0.2", + ":pin-project-lite-0.2", + ":socket2-0.6", + ":tokio-1", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +http_archive( + name = "indexmap-1.9.3.crate", + sha256 = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99", + strip_prefix = "indexmap-1.9.3", + urls = ["https://static.crates.io/crates/indexmap/1.9.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "indexmap-1", + srcs = [":indexmap-1.9.3.crate"], + crate = "indexmap", + crate_root = "indexmap-1.9.3.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :indexmap-1-build-script-run[out_dir])", + }, + rustc_flags = ["@$(location :indexmap-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [":hashbrown-0.12"], +) + +cargo.rust_binary( + name = "indexmap-1-build-script-build", + srcs = [":indexmap-1.9.3.crate"], + crate = "build_script_build", + crate_root = "indexmap-1.9.3.crate/build.rs", + edition = "2021", + visibility = [], + deps = [":autocfg-1"], +) + +reindeer_buildscript_run( + name = "indexmap-1-build-script-run", + package_name = "indexmap", + buildscript_rule = ":indexmap-1-build-script-build", + version = "1.9.3", +) + +http_archive( + name = "indexmap-2.14.0.crate", + sha256 = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9", + strip_prefix = "indexmap-2.14.0", + urls = ["https://static.crates.io/crates/indexmap/2.14.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "indexmap-2", + srcs = [":indexmap-2.14.0.crate"], + crate = "indexmap", + crate_root = "indexmap-2.14.0.crate/src/lib.rs", + edition = "2024", + features = [ + "default", + "std", + ], + visibility = [], + deps = [ + ":equivalent-1", + ":hashbrown-0.17", + ], +) + +http_archive( + name = "is_terminal_polyfill-1.70.2.crate", + sha256 = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695", + strip_prefix = "is_terminal_polyfill-1.70.2", + urls = ["https://static.crates.io/crates/is_terminal_polyfill/1.70.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "is_terminal_polyfill-1", + srcs = [":is_terminal_polyfill-1.70.2.crate"], + crate = "is_terminal_polyfill", + crate_root = "is_terminal_polyfill-1.70.2.crate/src/lib.rs", + edition = "2021", + features = ["default"], + visibility = [], +) + +http_archive( + name = "itertools-0.14.0.crate", + sha256 = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285", + strip_prefix = "itertools-0.14.0", + urls = ["https://static.crates.io/crates/itertools/0.14.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "itertools-0.14", + srcs = [":itertools-0.14.0.crate"], + crate = "itertools", + crate_root = "itertools-0.14.0.crate/src/lib.rs", + edition = "2018", + features = [ + "default", + "use_alloc", + "use_std", + ], + visibility = [], + deps = [":either-1"], +) + +http_archive( + name = "itoa-1.0.18.crate", + sha256 = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + strip_prefix = "itoa-1.0.18", + urls = ["https://static.crates.io/crates/itoa/1.0.18/download"], + visibility = [], +) + +cargo.rust_library( + name = "itoa-1", + srcs = [":itoa-1.0.18.crate"], + crate = "itoa", + crate_root = "itoa-1.0.18.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +alias( + name = "libc", + actual = ":libc-0.2", + visibility = ["PUBLIC"], +) + +http_archive( + name = "libc-0.2.186.crate", + sha256 = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66", + strip_prefix = "libc-0.2.186", + urls = ["https://static.crates.io/crates/libc/0.2.186/download"], + visibility = [], +) + +cargo.rust_library( + name = "libc-0.2", + srcs = [":libc-0.2.186.crate"], + crate = "libc", + crate_root = "libc-0.2.186.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :libc-0.2-build-script-run[out_dir])", + }, + features = [ + "default", + "std", + ], + rustc_flags = ["@$(location :libc-0.2-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "libc-0.2-build-script-build", + srcs = [":libc-0.2.186.crate"], + crate = "build_script_build", + crate_root = "libc-0.2.186.crate/build.rs", + edition = "2021", + features = [ + "default", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "libc-0.2-build-script-run", + package_name = "libc", + buildscript_rule = ":libc-0.2-build-script-build", + features = [ + "default", + "std", + ], + version = "0.2.186", +) + +http_archive( + name = "linux-raw-sys-0.12.1.crate", + sha256 = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + strip_prefix = "linux-raw-sys-0.12.1", + urls = ["https://static.crates.io/crates/linux-raw-sys/0.12.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "linux-raw-sys-0.12", + srcs = [":linux-raw-sys-0.12.1.crate"], + crate = "linux_raw_sys", + crate_root = "linux-raw-sys-0.12.1.crate/src/lib.rs", + edition = "2021", + features = [ + "auxvec", + "elf", + "errno", + "general", + "ioctl", + "no_std", + ], + visibility = [], +) + +http_archive( + name = "log-0.4.33.crate", + sha256 = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad", + strip_prefix = "log-0.4.33", + urls = ["https://static.crates.io/crates/log/0.4.33/download"], + visibility = [], +) + +cargo.rust_library( + name = "log-0.4", + srcs = [":log-0.4.33.crate"], + crate = "log", + crate_root = "log-0.4.33.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "matchit-0.7.3.crate", + sha256 = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94", + strip_prefix = "matchit-0.7.3", + urls = ["https://static.crates.io/crates/matchit/0.7.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "matchit-0.7", + srcs = [":matchit-0.7.3.crate"], + crate = "matchit", + crate_root = "matchit-0.7.3.crate/src/lib.rs", + edition = "2021", + features = ["default"], + visibility = [], +) + +http_archive( + name = "memchr-2.8.3.crate", + sha256 = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", + strip_prefix = "memchr-2.8.3", + urls = ["https://static.crates.io/crates/memchr/2.8.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "memchr-2", + srcs = [":memchr-2.8.3.crate"], + crate = "memchr", + crate_root = "memchr-2.8.3.crate/src/lib.rs", + edition = "2021", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "mime-0.3.17.crate", + sha256 = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a", + strip_prefix = "mime-0.3.17", + urls = ["https://static.crates.io/crates/mime/0.3.17/download"], + visibility = [], +) + +cargo.rust_library( + name = "mime-0.3", + srcs = [":mime-0.3.17.crate"], + crate = "mime", + crate_root = "mime-0.3.17.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +http_archive( + name = "mio-1.2.2.crate", + sha256 = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427", + strip_prefix = "mio-1.2.2", + urls = ["https://static.crates.io/crates/mio/1.2.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "mio-1", + srcs = [":mio-1.2.2.crate"], + crate = "mio", + crate_root = "mio-1.2.2.crate/src/lib.rs", + edition = "2021", + features = [ + "net", + "os-ext", + "os-poll", + ], + visibility = [], + deps = [":libc-0.2"], +) + +http_archive( + name = "once_cell-1.21.4.crate", + sha256 = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50", + strip_prefix = "once_cell-1.21.4", + urls = ["https://static.crates.io/crates/once_cell/1.21.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "once_cell-1", + srcs = [":once_cell-1.21.4.crate"], + crate = "once_cell", + crate_root = "once_cell-1.21.4.crate/src/lib.rs", + edition = "2021", + features = [ + "alloc", + "default", + "race", + "std", + ], + visibility = [], +) + +http_archive( + name = "opentelemetry-0.27.1.crate", + sha256 = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7", + strip_prefix = "opentelemetry-0.27.1", + urls = ["https://static.crates.io/crates/opentelemetry/0.27.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "opentelemetry-0.27", + srcs = [":opentelemetry-0.27.1.crate"], + crate = "opentelemetry", + crate_root = "opentelemetry-0.27.1.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "futures-core", + "futures-sink", + "internal-logs", + "logs", + "metrics", + "pin-project-lite", + "thiserror", + "trace", + "tracing", + ], + visibility = [], + deps = [ + ":futures-core-0.3", + ":futures-sink-0.3", + ":pin-project-lite-0.2", + ":thiserror-1", + ":tracing-0.1", + ], +) + +alias( + name = "opentelemetry-proto", + actual = ":opentelemetry-proto-0.27", + visibility = ["PUBLIC"], +) + +http_archive( + name = "opentelemetry-proto-0.27.0.crate", + sha256 = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6", + strip_prefix = "opentelemetry-proto-0.27.0", + urls = ["https://static.crates.io/crates/opentelemetry-proto/0.27.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "opentelemetry-proto-0.27", + srcs = [":opentelemetry-proto-0.27.0.crate"], + crate = "opentelemetry_proto", + crate_root = "opentelemetry-proto-0.27.0.crate/src/lib.rs", + edition = "2021", + features = [ + "gen-tonic", + "gen-tonic-messages", + "hex", + "logs", + "metrics", + "prost", + "serde", + "tonic", + "trace", + "with-serde", + ], + visibility = [], + deps = [ + ":hex-0.4", + ":opentelemetry-0.27", + ":opentelemetry_sdk-0.27", + ":prost-0.13", + ":serde-1", + ":tonic-0.12", + ], +) + +http_archive( + name = "opentelemetry_sdk-0.27.1.crate", + sha256 = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8", + strip_prefix = "opentelemetry_sdk-0.27.1", + urls = ["https://static.crates.io/crates/opentelemetry_sdk/0.27.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "opentelemetry_sdk-0.27", + srcs = [":opentelemetry_sdk-0.27.1.crate"], + crate = "opentelemetry_sdk", + crate_root = "opentelemetry_sdk-0.27.1.crate/src/lib.rs", + edition = "2021", + features = [ + "async-trait", + "glob", + "logs", + "metrics", + "percent-encoding", + "rand", + "serde_json", + "trace", + ], + visibility = [], + deps = [ + ":async-trait-0.1", + ":futures-channel-0.3", + ":futures-executor-0.3", + ":futures-util-0.3", + ":glob-0.3", + ":opentelemetry-0.27", + ":percent-encoding-2", + ":rand-0.8", + ":serde_json-1", + ":thiserror-1", + ], +) + +http_archive( + name = "percent-encoding-2.3.2.crate", + sha256 = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220", + strip_prefix = "percent-encoding-2.3.2", + urls = ["https://static.crates.io/crates/percent-encoding/2.3.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "percent-encoding-2", + srcs = [":percent-encoding-2.3.2.crate"], + crate = "percent_encoding", + crate_root = "percent-encoding-2.3.2.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "pin-project-1.1.13.crate", + sha256 = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924", + strip_prefix = "pin-project-1.1.13", + urls = ["https://static.crates.io/crates/pin-project/1.1.13/download"], + visibility = [], +) + +cargo.rust_library( + name = "pin-project-1", + srcs = [":pin-project-1.1.13.crate"], + crate = "pin_project", + crate_root = "pin-project-1.1.13.crate/src/lib.rs", + edition = "2021", + visibility = [], + deps = [":pin-project-internal-1"], +) + +http_archive( + name = "pin-project-internal-1.1.13.crate", + sha256 = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b", + strip_prefix = "pin-project-internal-1.1.13", + urls = ["https://static.crates.io/crates/pin-project-internal/1.1.13/download"], + visibility = [], +) + +cargo.rust_library( + name = "pin-project-internal-1", + srcs = [":pin-project-internal-1.1.13.crate"], + crate = "pin_project_internal", + crate_root = "pin-project-internal-1.1.13.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "pin-project-lite-0.2.17.crate", + sha256 = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd", + strip_prefix = "pin-project-lite-0.2.17", + urls = ["https://static.crates.io/crates/pin-project-lite/0.2.17/download"], + visibility = [], +) + +cargo.rust_library( + name = "pin-project-lite-0.2", + srcs = [":pin-project-lite-0.2.17.crate"], + crate = "pin_project_lite", + crate_root = "pin-project-lite-0.2.17.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +http_archive( + name = "ppv-lite86-0.2.21.crate", + sha256 = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9", + strip_prefix = "ppv-lite86-0.2.21", + urls = ["https://static.crates.io/crates/ppv-lite86/0.2.21/download"], + visibility = [], +) + +cargo.rust_library( + name = "ppv-lite86-0.2", + srcs = [":ppv-lite86-0.2.21.crate"], + crate = "ppv_lite86", + crate_root = "ppv-lite86-0.2.21.crate/src/lib.rs", + edition = "2021", + features = [ + "simd", + "std", + ], + visibility = [], + deps = [":zerocopy-0.8"], +) + +http_archive( + name = "proc-macro2-1.0.107.crate", + sha256 = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", + strip_prefix = "proc-macro2-1.0.107", + urls = ["https://static.crates.io/crates/proc-macro2/1.0.107/download"], + visibility = [], +) + +cargo.rust_library( + name = "proc-macro2-1", + srcs = [":proc-macro2-1.0.107.crate"], + crate = "proc_macro2", + crate_root = "proc-macro2-1.0.107.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :proc-macro2-1-build-script-run[out_dir])", + }, + features = [ + "default", + "proc-macro", + ], + rustc_flags = ["@$(location :proc-macro2-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [":unicode-ident-1"], +) + +cargo.rust_binary( + name = "proc-macro2-1-build-script-build", + srcs = [":proc-macro2-1.0.107.crate"], + crate = "build_script_build", + crate_root = "proc-macro2-1.0.107.crate/build.rs", + edition = "2021", + features = [ + "default", + "proc-macro", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "proc-macro2-1-build-script-run", + package_name = "proc-macro2", + buildscript_rule = ":proc-macro2-1-build-script-build", + features = [ + "default", + "proc-macro", + ], + version = "1.0.107", +) + +alias( + name = "prost", + actual = ":prost-0.13", + visibility = ["PUBLIC"], +) + +http_archive( + name = "prost-0.13.5.crate", + sha256 = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5", + strip_prefix = "prost-0.13.5", + urls = ["https://static.crates.io/crates/prost/0.13.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "prost-0.13", + srcs = [":prost-0.13.5.crate"], + crate = "prost", + crate_root = "prost-0.13.5.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "derive", + "std", + ], + visibility = [], + deps = [ + ":bytes-1", + ":prost-derive-0.13", + ], +) + +http_archive( + name = "prost-derive-0.13.5.crate", + sha256 = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d", + strip_prefix = "prost-derive-0.13.5", + urls = ["https://static.crates.io/crates/prost-derive/0.13.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "prost-derive-0.13", + srcs = [":prost-derive-0.13.5.crate"], + crate = "prost_derive", + crate_root = "prost-derive-0.13.5.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":anyhow-1", + ":itertools-0.14", + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "quote-1.0.47.crate", + sha256 = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", + strip_prefix = "quote-1.0.47", + urls = ["https://static.crates.io/crates/quote/1.0.47/download"], + visibility = [], +) + +cargo.rust_library( + name = "quote-1", + srcs = [":quote-1.0.47.crate"], + crate = "quote", + crate_root = "quote-1.0.47.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :quote-1-build-script-run[out_dir])", + }, + features = [ + "default", + "proc-macro", + ], + rustc_flags = ["@$(location :quote-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [":proc-macro2-1"], +) + +cargo.rust_binary( + name = "quote-1-build-script-build", + srcs = [":quote-1.0.47.crate"], + crate = "build_script_build", + crate_root = "quote-1.0.47.crate/build.rs", + edition = "2021", + features = [ + "default", + "proc-macro", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "quote-1-build-script-run", + package_name = "quote", + buildscript_rule = ":quote-1-build-script-build", + features = [ + "default", + "proc-macro", + ], + version = "1.0.47", +) + +http_archive( + name = "rand-0.8.7.crate", + sha256 = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a", + strip_prefix = "rand-0.8.7", + urls = ["https://static.crates.io/crates/rand/0.8.7/download"], + visibility = [], +) + +cargo.rust_library( + name = "rand-0.8", + srcs = [":rand-0.8.7.crate"], + crate = "rand", + crate_root = "rand-0.8.7.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "default", + "getrandom", + "libc", + "rand_chacha", + "small_rng", + "std", + "std_rng", + ], + visibility = [], + deps = [ + ":libc-0.2", + ":rand_chacha-0.3", + ":rand_core-0.6", + ], +) + +http_archive( + name = "rand_chacha-0.3.1.crate", + sha256 = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88", + strip_prefix = "rand_chacha-0.3.1", + urls = ["https://static.crates.io/crates/rand_chacha/0.3.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "rand_chacha-0.3", + srcs = [":rand_chacha-0.3.1.crate"], + crate = "rand_chacha", + crate_root = "rand_chacha-0.3.1.crate/src/lib.rs", + edition = "2018", + features = ["std"], + visibility = [], + deps = [ + ":ppv-lite86-0.2", + ":rand_core-0.6", + ], +) + +http_archive( + name = "rand_core-0.6.4.crate", + sha256 = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c", + strip_prefix = "rand_core-0.6.4", + urls = ["https://static.crates.io/crates/rand_core/0.6.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "rand_core-0.6", + srcs = [":rand_core-0.6.4.crate"], + crate = "rand_core", + crate_root = "rand_core-0.6.4.crate/src/lib.rs", + edition = "2018", + features = [ + "alloc", + "getrandom", + "std", + ], + visibility = [], + deps = [":getrandom-0.2"], +) + +http_archive( + name = "rustix-1.1.4.crate", + sha256 = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190", + strip_prefix = "rustix-1.1.4", + urls = ["https://static.crates.io/crates/rustix/1.1.4/download"], + visibility = [], +) + +cargo.rust_library( + name = "rustix-1", + srcs = [":rustix-1.1.4.crate"], + crate = "rustix", + crate_root = "rustix-1.1.4.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :rustix-1-build-script-run[out_dir])", + }, + features = [ + "alloc", + "default", + "fs", + "std", + ], + rustc_flags = ["@$(location :rustix-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [ + ":bitflags-2", + ":linux-raw-sys-0.12", + ], +) + +cargo.rust_binary( + name = "rustix-1-build-script-build", + srcs = [":rustix-1.1.4.crate"], + crate = "build_script_build", + crate_root = "rustix-1.1.4.crate/build.rs", + edition = "2021", + features = [ + "alloc", + "default", + "fs", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "rustix-1-build-script-run", + package_name = "rustix", + buildscript_rule = ":rustix-1-build-script-build", + features = [ + "alloc", + "default", + "fs", + "std", + ], + version = "1.1.4", +) + +http_archive( + name = "rustversion-1.0.23.crate", + sha256 = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f", + strip_prefix = "rustversion-1.0.23", + urls = ["https://static.crates.io/crates/rustversion/1.0.23/download"], + visibility = [], +) + +cargo.rust_library( + name = "rustversion-1", + srcs = [":rustversion-1.0.23.crate"], + crate = "rustversion", + crate_root = "rustversion-1.0.23.crate/src/lib.rs", + edition = "2018", + env = { + "OUT_DIR": "$(location :rustversion-1-build-script-run[out_dir])", + }, + proc_macro = True, + rustc_flags = ["@$(location :rustversion-1-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "rustversion-1-build-script-build", + srcs = [":rustversion-1.0.23.crate"], + crate = "build_script_build", + crate_root = "rustversion-1.0.23.crate/build/build.rs", + edition = "2018", + visibility = [], +) + +reindeer_buildscript_run( + name = "rustversion-1-build-script-run", + package_name = "rustversion", + buildscript_rule = ":rustversion-1-build-script-build", + version = "1.0.23", +) + +http_archive( + name = "ryu-1.0.23.crate", + sha256 = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + strip_prefix = "ryu-1.0.23", + urls = ["https://static.crates.io/crates/ryu/1.0.23/download"], + visibility = [], +) + +cargo.rust_library( + name = "ryu-1", + srcs = [":ryu-1.0.23.crate"], + crate = "ryu", + crate_root = "ryu-1.0.23.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "same-file-1.0.6.crate", + sha256 = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + strip_prefix = "same-file-1.0.6", + urls = ["https://static.crates.io/crates/same-file/1.0.6/download"], + visibility = [], +) + +cargo.rust_library( + name = "same-file-1", + srcs = [":same-file-1.0.6.crate"], + crate = "same_file", + crate_root = "same-file-1.0.6.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +alias( + name = "serde", + actual = ":serde-1", + visibility = ["PUBLIC"], +) + +http_archive( + name = "serde-1.0.229.crate", + sha256 = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba", + strip_prefix = "serde-1.0.229", + urls = ["https://static.crates.io/crates/serde/1.0.229/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde-1", + srcs = [":serde-1.0.229.crate"], + crate = "serde", + crate_root = "serde-1.0.229.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :serde-1-build-script-run[out_dir])", + }, + features = [ + "default", + "derive", + "serde_derive", + "std", + ], + rustc_flags = ["@$(location :serde-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [ + ":serde_core-1", + ":serde_derive-1", + ], +) + +cargo.rust_binary( + name = "serde-1-build-script-build", + srcs = [":serde-1.0.229.crate"], + crate = "build_script_build", + crate_root = "serde-1.0.229.crate/build.rs", + edition = "2021", + features = [ + "default", + "derive", + "serde_derive", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "serde-1-build-script-run", + package_name = "serde", + buildscript_rule = ":serde-1-build-script-build", + features = [ + "default", + "derive", + "serde_derive", + "std", + ], + version = "1.0.229", +) + +http_archive( + name = "serde_core-1.0.229.crate", + sha256 = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48", + strip_prefix = "serde_core-1.0.229", + urls = ["https://static.crates.io/crates/serde_core/1.0.229/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde_core-1", + srcs = [":serde_core-1.0.229.crate"], + crate = "serde_core", + crate_root = "serde_core-1.0.229.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :serde_core-1-build-script-run[out_dir])", + }, + features = [ + "alloc", + "result", + "std", + ], + rustc_flags = ["@$(location :serde_core-1-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "serde_core-1-build-script-build", + srcs = [":serde_core-1.0.229.crate"], + crate = "build_script_build", + crate_root = "serde_core-1.0.229.crate/build.rs", + edition = "2021", + features = [ + "alloc", + "result", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "serde_core-1-build-script-run", + package_name = "serde_core", + buildscript_rule = ":serde_core-1-build-script-build", + features = [ + "alloc", + "result", + "std", + ], + version = "1.0.229", +) + +http_archive( + name = "serde_derive-1.0.229.crate", + sha256 = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348", + strip_prefix = "serde_derive-1.0.229", + urls = ["https://static.crates.io/crates/serde_derive/1.0.229/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde_derive-1", + srcs = [":serde_derive-1.0.229.crate"], + crate = "serde_derive", + crate_root = "serde_derive-1.0.229.crate/src/lib.rs", + edition = "2021", + features = ["default"], + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-3", + ], +) + +alias( + name = "serde_json", + actual = ":serde_json-1", + visibility = ["PUBLIC"], +) + +http_archive( + name = "serde_json-1.0.151.crate", + sha256 = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14", + strip_prefix = "serde_json-1.0.151", + urls = ["https://static.crates.io/crates/serde_json/1.0.151/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde_json-1", + srcs = [":serde_json-1.0.151.crate"], + crate = "serde_json", + crate_root = "serde_json-1.0.151.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :serde_json-1-build-script-run[out_dir])", + }, + features = [ + "default", + "raw_value", + "std", + ], + rustc_flags = ["@$(location :serde_json-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [ + ":itoa-1", + ":memchr-2", + ":serde_core-1", + ":zmij-1", + ], +) + +cargo.rust_binary( + name = "serde_json-1-build-script-build", + srcs = [":serde_json-1.0.151.crate"], + crate = "build_script_build", + crate_root = "serde_json-1.0.151.crate/build.rs", + edition = "2021", + features = [ + "default", + "raw_value", + "std", + ], + visibility = [], +) + +reindeer_buildscript_run( + name = "serde_json-1-build-script-run", + package_name = "serde_json", + buildscript_rule = ":serde_json-1-build-script-build", + features = [ + "default", + "raw_value", + "std", + ], + version = "1.0.151", +) + +http_archive( + name = "serde_path_to_error-0.1.20.crate", + sha256 = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457", + strip_prefix = "serde_path_to_error-0.1.20", + urls = ["https://static.crates.io/crates/serde_path_to_error/0.1.20/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde_path_to_error-0.1", + srcs = [":serde_path_to_error-0.1.20.crate"], + crate = "serde_path_to_error", + crate_root = "serde_path_to_error-0.1.20.crate/src/lib.rs", + edition = "2021", + visibility = [], + deps = [ + ":itoa-1", + ":serde_core-1", + ], +) + +http_archive( + name = "serde_urlencoded-0.7.1.crate", + sha256 = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd", + strip_prefix = "serde_urlencoded-0.7.1", + urls = ["https://static.crates.io/crates/serde_urlencoded/0.7.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "serde_urlencoded-0.7", + srcs = [":serde_urlencoded-0.7.1.crate"], + crate = "serde_urlencoded", + crate_root = "serde_urlencoded-0.7.1.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [ + ":form_urlencoded-1", + ":itoa-1", + ":ryu-1", + ":serde-1", + ], +) + +alias( + name = "sha2", + actual = ":sha2-0.11", + visibility = ["PUBLIC"], +) + +http_archive( + name = "sha2-0.11.0.crate", + sha256 = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4", + strip_prefix = "sha2-0.11.0", + urls = ["https://static.crates.io/crates/sha2/0.11.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "sha2-0.11", + srcs = [":sha2-0.11.0.crate"], + crate = "sha2", + crate_root = "sha2-0.11.0.crate/src/lib.rs", + edition = "2024", + features = [ + "alloc", + "default", + "oid", + ], + visibility = [], + deps = [ + ":cfg-if-1", + ":cpufeatures-0.3", + ":digest-0.11", + ], +) + +http_archive( + name = "signal-hook-registry-1.4.8.crate", + sha256 = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b", + strip_prefix = "signal-hook-registry-1.4.8", + urls = ["https://static.crates.io/crates/signal-hook-registry/1.4.8/download"], + visibility = [], +) + +cargo.rust_library( + name = "signal-hook-registry-1", + srcs = [":signal-hook-registry-1.4.8.crate"], + crate = "signal_hook_registry", + crate_root = "signal-hook-registry-1.4.8.crate/src/lib.rs", + edition = "2015", + visibility = [], + deps = [ + ":errno-0.3", + ":libc-0.2", + ], +) + +http_archive( + name = "slab-0.4.12.crate", + sha256 = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5", + strip_prefix = "slab-0.4.12", + urls = ["https://static.crates.io/crates/slab/0.4.12/download"], + visibility = [], +) + +cargo.rust_library( + name = "slab-0.4", + srcs = [":slab-0.4.12.crate"], + crate = "slab", + crate_root = "slab-0.4.12.crate/src/lib.rs", + edition = "2018", + features = [ + "default", + "std", + ], + visibility = [], +) + +http_archive( + name = "smallvec-1.15.2.crate", + sha256 = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90", + strip_prefix = "smallvec-1.15.2", + urls = ["https://static.crates.io/crates/smallvec/1.15.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "smallvec-1", + srcs = [":smallvec-1.15.2.crate"], + crate = "smallvec", + crate_root = "smallvec-1.15.2.crate/src/lib.rs", + edition = "2018", + features = [ + "const_generics", + "const_new", + ], + visibility = [], +) + +http_archive( + name = "socket2-0.5.10.crate", + sha256 = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678", + strip_prefix = "socket2-0.5.10", + urls = ["https://static.crates.io/crates/socket2/0.5.10/download"], + visibility = [], +) + +cargo.rust_library( + name = "socket2-0.5", + srcs = [":socket2-0.5.10.crate"], + crate = "socket2", + crate_root = "socket2-0.5.10.crate/src/lib.rs", + edition = "2021", + features = ["all"], + visibility = [], + deps = [":libc-0.2"], +) + +http_archive( + name = "socket2-0.6.5.crate", + sha256 = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4", + strip_prefix = "socket2-0.6.5", + urls = ["https://static.crates.io/crates/socket2/0.6.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "socket2-0.6", + srcs = [":socket2-0.6.5.crate"], + crate = "socket2", + crate_root = "socket2-0.6.5.crate/src/lib.rs", + edition = "2021", + features = ["all"], + visibility = [], + deps = [":libc-0.2"], +) + +http_archive( + name = "strsim-0.11.1.crate", + sha256 = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f", + strip_prefix = "strsim-0.11.1", + urls = ["https://static.crates.io/crates/strsim/0.11.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "strsim-0.11", + srcs = [":strsim-0.11.1.crate"], + crate = "strsim", + crate_root = "strsim-0.11.1.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +http_archive( + name = "syn-2.0.119.crate", + sha256 = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297", + strip_prefix = "syn-2.0.119", + urls = ["https://static.crates.io/crates/syn/2.0.119/download"], + visibility = [], +) + +cargo.rust_library( + name = "syn-2", + srcs = [":syn-2.0.119.crate"], + crate = "syn", + crate_root = "syn-2.0.119.crate/src/lib.rs", + edition = "2021", + features = [ + "clone-impls", + "default", + "derive", + "extra-traits", + "full", + "parsing", + "printing", + "proc-macro", + "visit-mut", + ], + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":unicode-ident-1", + ], +) + +http_archive( + name = "syn-3.0.3.crate", + sha256 = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3", + strip_prefix = "syn-3.0.3", + urls = ["https://static.crates.io/crates/syn/3.0.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "syn-3", + srcs = [":syn-3.0.3.crate"], + crate = "syn", + crate_root = "syn-3.0.3.crate/src/lib.rs", + edition = "2021", + features = [ + "clone-impls", + "default", + "derive", + "full", + "parsing", + "printing", + "proc-macro", + "visit-mut", + ], + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":unicode-ident-1", + ], +) + +http_archive( + name = "sync_wrapper-1.0.2.crate", + sha256 = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263", + strip_prefix = "sync_wrapper-1.0.2", + urls = ["https://static.crates.io/crates/sync_wrapper/1.0.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "sync_wrapper-1", + srcs = [":sync_wrapper-1.0.2.crate"], + crate = "sync_wrapper", + crate_root = "sync_wrapper-1.0.2.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +alias( + name = "tar", + actual = ":tar-0.4", + visibility = ["PUBLIC"], +) + +http_archive( + name = "tar-0.4.46.crate", + sha256 = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840", + strip_prefix = "tar-0.4.46", + urls = ["https://static.crates.io/crates/tar/0.4.46/download"], + visibility = [], +) + +cargo.rust_library( + name = "tar-0.4", + srcs = [":tar-0.4.46.crate"], + crate = "tar", + crate_root = "tar-0.4.46.crate/src/lib.rs", + edition = "2021", + visibility = [], + deps = [ + ":filetime-0.2", + ":libc-0.2", + ], +) + +alias( + name = "tempfile", + actual = ":tempfile-3", + visibility = ["PUBLIC"], +) + +http_archive( + name = "tempfile-3.27.0.crate", + sha256 = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd", + strip_prefix = "tempfile-3.27.0", + urls = ["https://static.crates.io/crates/tempfile/3.27.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "tempfile-3", + srcs = [":tempfile-3.27.0.crate"], + crate = "tempfile", + crate_root = "tempfile-3.27.0.crate/src/lib.rs", + edition = "2021", + features = [ + "default", + "getrandom", + ], + visibility = [], + deps = [ + ":fastrand-2", + ":getrandom-0.4", + ":once_cell-1", + ":rustix-1", + ], +) + +http_archive( + name = "thiserror-1.0.69.crate", + sha256 = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52", + strip_prefix = "thiserror-1.0.69", + urls = ["https://static.crates.io/crates/thiserror/1.0.69/download"], + visibility = [], +) + +cargo.rust_library( + name = "thiserror-1", + srcs = [":thiserror-1.0.69.crate"], + crate = "thiserror", + crate_root = "thiserror-1.0.69.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :thiserror-1-build-script-run[out_dir])", + }, + rustc_flags = ["@$(location :thiserror-1-build-script-run[rustc_flags])"], + visibility = [], + deps = [":thiserror-impl-1"], +) + +cargo.rust_binary( + name = "thiserror-1-build-script-build", + srcs = [":thiserror-1.0.69.crate"], + crate = "build_script_build", + crate_root = "thiserror-1.0.69.crate/build.rs", + edition = "2021", + visibility = [], +) + +reindeer_buildscript_run( + name = "thiserror-1-build-script-run", + package_name = "thiserror", + buildscript_rule = ":thiserror-1-build-script-build", + version = "1.0.69", +) + +http_archive( + name = "thiserror-impl-1.0.69.crate", + sha256 = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1", + strip_prefix = "thiserror-impl-1.0.69", + urls = ["https://static.crates.io/crates/thiserror-impl/1.0.69/download"], + visibility = [], +) + +cargo.rust_library( + name = "thiserror-impl-1", + srcs = [":thiserror-impl-1.0.69.crate"], + crate = "thiserror_impl", + crate_root = "thiserror-impl-1.0.69.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +alias( + name = "tokio", + actual = ":tokio-1", + visibility = ["PUBLIC"], +) + +http_archive( + name = "tokio-1.53.1.crate", + sha256 = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed", + strip_prefix = "tokio-1.53.1", + urls = ["https://static.crates.io/crates/tokio/1.53.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "tokio-1", + srcs = [":tokio-1.53.1.crate"], + crate = "tokio", + crate_root = "tokio-1.53.1.crate/src/lib.rs", + edition = "2021", + features = [ + "bytes", + "default", + "fs", + "io-std", + "io-util", + "libc", + "macros", + "mio", + "net", + "process", + "rt", + "rt-multi-thread", + "signal", + "signal-hook-registry", + "socket2", + "sync", + "time", + "tokio-macros", + ], + visibility = [], + deps = [ + ":bytes-1", + ":libc-0.2", + ":mio-1", + ":pin-project-lite-0.2", + ":signal-hook-registry-1", + ":socket2-0.6", + ":tokio-macros-2", + ], +) + +http_archive( + name = "tokio-macros-2.7.0.crate", + sha256 = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496", + strip_prefix = "tokio-macros-2.7.0", + urls = ["https://static.crates.io/crates/tokio-macros/2.7.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "tokio-macros-2", + srcs = [":tokio-macros-2.7.0.crate"], + crate = "tokio_macros", + crate_root = "tokio-macros-2.7.0.crate/src/lib.rs", + edition = "2021", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "tokio-stream-0.1.18.crate", + sha256 = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70", + strip_prefix = "tokio-stream-0.1.18", + urls = ["https://static.crates.io/crates/tokio-stream/0.1.18/download"], + visibility = [], +) + +cargo.rust_library( + name = "tokio-stream-0.1", + srcs = [":tokio-stream-0.1.18.crate"], + crate = "tokio_stream", + crate_root = "tokio-stream-0.1.18.crate/src/lib.rs", + edition = "2021", + features = ["net"], + visibility = [], + deps = [ + ":futures-core-0.3", + ":pin-project-lite-0.2", + ":tokio-1", + ], +) + +http_archive( + name = "tokio-util-0.7.18.crate", + sha256 = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098", + strip_prefix = "tokio-util-0.7.18", + urls = ["https://static.crates.io/crates/tokio-util/0.7.18/download"], + visibility = [], +) + +cargo.rust_library( + name = "tokio-util-0.7", + srcs = [":tokio-util-0.7.18.crate"], + crate = "tokio_util", + crate_root = "tokio-util-0.7.18.crate/src/lib.rs", + edition = "2021", + features = [ + "codec", + "default", + "io", + ], + visibility = [], + deps = [ + ":bytes-1", + ":futures-core-0.3", + ":futures-sink-0.3", + ":pin-project-lite-0.2", + ":tokio-1", + ], +) + +alias( + name = "tonic", + actual = ":tonic-0.12", + visibility = ["PUBLIC"], +) + +http_archive( + name = "tonic-0.12.3.crate", + sha256 = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52", + strip_prefix = "tonic-0.12.3", + urls = ["https://static.crates.io/crates/tonic/0.12.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "tonic-0.12", + srcs = [":tonic-0.12.3.crate"], + crate = "tonic", + crate_root = "tonic-0.12.3.crate/src/lib.rs", + edition = "2021", + features = [ + "channel", + "codegen", + "default", + "prost", + "router", + "server", + "transport", + ], + visibility = [], + deps = [ + ":async-stream-0.3", + ":async-trait-0.1", + ":axum-0.7", + ":base64-0.22", + ":bytes-1", + ":h2-0.4", + ":http-1", + ":http-body-1", + ":http-body-util-0.1", + ":hyper-1", + ":hyper-timeout-0.5", + ":hyper-util-0.1", + ":percent-encoding-2", + ":pin-project-1", + ":prost-0.13", + ":socket2-0.5", + ":tokio-1", + ":tokio-stream-0.1", + ":tower-0.4", + ":tower-layer-0.3", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +http_archive( + name = "tower-0.4.13.crate", + sha256 = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c", + strip_prefix = "tower-0.4.13", + urls = ["https://static.crates.io/crates/tower/0.4.13/download"], + visibility = [], +) + +cargo.rust_library( + name = "tower-0.4", + srcs = [":tower-0.4.13.crate"], + crate = "tower", + crate_root = "tower-0.4.13.crate/src/lib.rs", + edition = "2018", + features = [ + "__common", + "balance", + "buffer", + "discover", + "futures-core", + "futures-util", + "indexmap", + "limit", + "load", + "make", + "pin-project", + "pin-project-lite", + "rand", + "ready-cache", + "slab", + "tokio", + "tokio-util", + "tracing", + "util", + ], + visibility = [], + deps = [ + ":futures-core-0.3", + ":futures-util-0.3", + ":indexmap-1", + ":pin-project-1", + ":pin-project-lite-0.2", + ":rand-0.8", + ":slab-0.4", + ":tokio-1", + ":tokio-util-0.7", + ":tower-layer-0.3", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +http_archive( + name = "tower-0.5.3.crate", + sha256 = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4", + strip_prefix = "tower-0.5.3", + urls = ["https://static.crates.io/crates/tower/0.5.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "tower-0.5", + srcs = [":tower-0.5.3.crate"], + crate = "tower", + crate_root = "tower-0.5.3.crate/src/lib.rs", + edition = "2018", + features = [ + "futures-core", + "futures-util", + "log", + "make", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tracing", + "util", + ], + visibility = [], + deps = [ + ":futures-core-0.3", + ":futures-util-0.3", + ":pin-project-lite-0.2", + ":sync_wrapper-1", + ":tokio-1", + ":tower-layer-0.3", + ":tower-service-0.3", + ":tracing-0.1", + ], +) + +http_archive( + name = "tower-layer-0.3.3.crate", + sha256 = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e", + strip_prefix = "tower-layer-0.3.3", + urls = ["https://static.crates.io/crates/tower-layer/0.3.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "tower-layer-0.3", + srcs = [":tower-layer-0.3.3.crate"], + crate = "tower_layer", + crate_root = "tower-layer-0.3.3.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +http_archive( + name = "tower-service-0.3.3.crate", + sha256 = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3", + strip_prefix = "tower-service-0.3.3", + urls = ["https://static.crates.io/crates/tower-service/0.3.3/download"], + visibility = [], +) + +cargo.rust_library( + name = "tower-service-0.3", + srcs = [":tower-service-0.3.3.crate"], + crate = "tower_service", + crate_root = "tower-service-0.3.3.crate/src/lib.rs", + edition = "2018", + visibility = [], +) + +http_archive( + name = "tracing-0.1.44.crate", + sha256 = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100", + strip_prefix = "tracing-0.1.44", + urls = ["https://static.crates.io/crates/tracing/0.1.44/download"], + visibility = [], +) + +cargo.rust_library( + name = "tracing-0.1", + srcs = [":tracing-0.1.44.crate"], + crate = "tracing", + crate_root = "tracing-0.1.44.crate/src/lib.rs", + edition = "2018", + features = [ + "attributes", + "default", + "log", + "std", + "tracing-attributes", + ], + visibility = [], + deps = [ + ":log-0.4", + ":pin-project-lite-0.2", + ":tracing-attributes-0.1", + ":tracing-core-0.1", + ], +) + +http_archive( + name = "tracing-attributes-0.1.31.crate", + sha256 = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da", + strip_prefix = "tracing-attributes-0.1.31", + urls = ["https://static.crates.io/crates/tracing-attributes/0.1.31/download"], + visibility = [], +) + +cargo.rust_library( + name = "tracing-attributes-0.1", + srcs = [":tracing-attributes-0.1.31.crate"], + crate = "tracing_attributes", + crate_root = "tracing-attributes-0.1.31.crate/src/lib.rs", + edition = "2018", + proc_macro = True, + visibility = [], + deps = [ + ":proc-macro2-1", + ":quote-1", + ":syn-2", + ], +) + +http_archive( + name = "tracing-core-0.1.36.crate", + sha256 = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a", + strip_prefix = "tracing-core-0.1.36", + urls = ["https://static.crates.io/crates/tracing-core/0.1.36/download"], + visibility = [], +) + +cargo.rust_library( + name = "tracing-core-0.1", + srcs = [":tracing-core-0.1.36.crate"], + crate = "tracing_core", + crate_root = "tracing-core-0.1.36.crate/src/lib.rs", + edition = "2018", + features = [ + "once_cell", + "std", + ], + visibility = [], + deps = [":once_cell-1"], +) + +http_archive( + name = "try-lock-0.2.5.crate", + sha256 = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b", + strip_prefix = "try-lock-0.2.5", + urls = ["https://static.crates.io/crates/try-lock/0.2.5/download"], + visibility = [], +) + +cargo.rust_library( + name = "try-lock-0.2", + srcs = [":try-lock-0.2.5.crate"], + crate = "try_lock", + crate_root = "try-lock-0.2.5.crate/src/lib.rs", + edition = "2015", + visibility = [], +) + +http_archive( + name = "typenum-1.20.1.crate", + sha256 = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + strip_prefix = "typenum-1.20.1", + urls = ["https://static.crates.io/crates/typenum/1.20.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "typenum-1", + srcs = [":typenum-1.20.1.crate"], + crate = "typenum", + crate_root = "typenum-1.20.1.crate/src/lib.rs", + edition = "2018", + features = ["const-generics"], + visibility = [], +) + +http_archive( + name = "unicode-ident-1.0.24.crate", + sha256 = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", + strip_prefix = "unicode-ident-1.0.24", + urls = ["https://static.crates.io/crates/unicode-ident/1.0.24/download"], + visibility = [], +) + +cargo.rust_library( + name = "unicode-ident-1", + srcs = [":unicode-ident-1.0.24.crate"], + crate = "unicode_ident", + crate_root = "unicode-ident-1.0.24.crate/src/lib.rs", + edition = "2021", + visibility = [], +) + +http_archive( + name = "utf8parse-0.2.2.crate", + sha256 = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821", + strip_prefix = "utf8parse-0.2.2", + urls = ["https://static.crates.io/crates/utf8parse/0.2.2/download"], + visibility = [], +) + +cargo.rust_library( + name = "utf8parse-0.2", + srcs = [":utf8parse-0.2.2.crate"], + crate = "utf8parse", + crate_root = "utf8parse-0.2.2.crate/src/lib.rs", + edition = "2018", + features = ["default"], + visibility = [], +) + +alias( + name = "walkdir", + actual = ":walkdir-2", + visibility = ["PUBLIC"], +) + +http_archive( + name = "walkdir-2.5.0.crate", + sha256 = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b", + strip_prefix = "walkdir-2.5.0", + urls = ["https://static.crates.io/crates/walkdir/2.5.0/download"], + visibility = [], +) + +cargo.rust_library( + name = "walkdir-2", + srcs = [":walkdir-2.5.0.crate"], + crate = "walkdir", + crate_root = "walkdir-2.5.0.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [":same-file-1"], +) + +http_archive( + name = "want-0.3.1.crate", + sha256 = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e", + strip_prefix = "want-0.3.1", + urls = ["https://static.crates.io/crates/want/0.3.1/download"], + visibility = [], +) + +cargo.rust_library( + name = "want-0.3", + srcs = [":want-0.3.1.crate"], + crate = "want", + crate_root = "want-0.3.1.crate/src/lib.rs", + edition = "2018", + visibility = [], + deps = [":try-lock-0.2"], +) + +http_archive( + name = "zerocopy-0.8.55.crate", + sha256 = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb", + strip_prefix = "zerocopy-0.8.55", + urls = ["https://static.crates.io/crates/zerocopy/0.8.55/download"], + visibility = [], +) + +cargo.rust_library( + name = "zerocopy-0.8", + srcs = [":zerocopy-0.8.55.crate"], + crate = "zerocopy", + crate_root = "zerocopy-0.8.55.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :zerocopy-0.8-build-script-run[out_dir])", + }, + features = ["simd"], + rustc_flags = ["@$(location :zerocopy-0.8-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "zerocopy-0.8-build-script-build", + srcs = [":zerocopy-0.8.55.crate"], + crate = "build_script_build", + crate_root = "zerocopy-0.8.55.crate/build.rs", + edition = "2021", + features = ["simd"], + visibility = [], +) + +reindeer_buildscript_run( + name = "zerocopy-0.8-build-script-run", + package_name = "zerocopy", + buildscript_rule = ":zerocopy-0.8-build-script-build", + features = ["simd"], + version = "0.8.55", +) + +http_archive( + name = "zmij-1.0.23.crate", + sha256 = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b", + strip_prefix = "zmij-1.0.23", + urls = ["https://static.crates.io/crates/zmij/1.0.23/download"], + visibility = [], +) + +cargo.rust_library( + name = "zmij-1", + srcs = [":zmij-1.0.23.crate"], + crate = "zmij", + crate_root = "zmij-1.0.23.crate/src/lib.rs", + edition = "2021", + env = { + "OUT_DIR": "$(location :zmij-1-build-script-run[out_dir])", + }, + rustc_flags = ["@$(location :zmij-1-build-script-run[rustc_flags])"], + visibility = [], +) + +cargo.rust_binary( + name = "zmij-1-build-script-build", + srcs = [":zmij-1.0.23.crate"], + crate = "build_script_build", + crate_root = "zmij-1.0.23.crate/build.rs", + edition = "2021", + visibility = [], +) + +reindeer_buildscript_run( + name = "zmij-1-build-script-run", + package_name = "zmij", + buildscript_rule = ":zmij-1-build-script-build", + version = "1.0.23", +) diff --git a/rust/third-party/PACKAGE b/rust/third-party/PACKAGE new file mode 100644 index 000000000..53ddaa30a --- /dev/null +++ b/rust/third-party/PACKAGE @@ -0,0 +1,8 @@ +load("@prelude//rust:cargo_package.bzl", "set_reindeer_platforms") + +set_reindeer_platforms( + select({ + "prelude//abi/constraints:musl": "x86_64-linux-musl", + "DEFAULT": "x86_64-linux", + }), +) diff --git a/rust/third-party/fixups/README.md b/rust/third-party/fixups/README.md new file mode 100644 index 000000000..0093edebf --- /dev/null +++ b/rust/third-party/fixups/README.md @@ -0,0 +1,6 @@ +# Reindeer fixups + +Every reachable Cargo build script is reviewed explicitly. `run = false` means +the published crate builds correctly from its manifest-declared Rust sources +for the currently admitted target without executing that script. A dependency +update must regenerate the graph and re-review this list. diff --git a/rust/third-party/fixups/anyhow/fixups.toml b/rust/third-party/fixups/anyhow/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/anyhow/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/getrandom/fixups.toml b/rust/third-party/fixups/getrandom/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/getrandom/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/httparse/fixups.toml b/rust/third-party/fixups/httparse/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/httparse/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/indexmap/fixups.toml b/rust/third-party/fixups/indexmap/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/indexmap/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/libc/fixups.toml b/rust/third-party/fixups/libc/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/libc/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/proc-macro2/fixups.toml b/rust/third-party/fixups/proc-macro2/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/proc-macro2/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/quote/fixups.toml b/rust/third-party/fixups/quote/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/quote/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/rustix/fixups.toml b/rust/third-party/fixups/rustix/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/rustix/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/rustversion/fixups.toml b/rust/third-party/fixups/rustversion/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/rustversion/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/serde/fixups.toml b/rust/third-party/fixups/serde/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/serde/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/serde_core/fixups.toml b/rust/third-party/fixups/serde_core/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/serde_core/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/serde_json/fixups.toml b/rust/third-party/fixups/serde_json/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/serde_json/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/thiserror/fixups.toml b/rust/third-party/fixups/thiserror/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/thiserror/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/windows_x86_64_gnu/fixups.toml b/rust/third-party/fixups/windows_x86_64_gnu/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/windows_x86_64_gnu/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/windows_x86_64_msvc/fixups.toml b/rust/third-party/fixups/windows_x86_64_msvc/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/windows_x86_64_msvc/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/zerocopy/fixups.toml b/rust/third-party/fixups/zerocopy/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/zerocopy/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/third-party/fixups/zmij/fixups.toml b/rust/third-party/fixups/zmij/fixups.toml new file mode 100644 index 000000000..89f3cd5db --- /dev/null +++ b/rust/third-party/fixups/zmij/fixups.toml @@ -0,0 +1 @@ +buildscript.run = true diff --git a/rust/workspace-contract.test.sh b/rust/workspace-contract.test.sh index 541b141d8..14c1f8292 100644 --- a/rust/workspace-contract.test.sh +++ b/rust/workspace-contract.test.sh @@ -34,7 +34,7 @@ cargo metadata \ --no-deps \ --format-version 1 >"$metadata" -expected_packages='["buck2-closure-tool","buck2-package-evidence","buck2-portable-toolchain","buck2-portable-toolchain-fixture","buck2-tool-core","otel-scrape","otelite"]' +expected_packages='["buck2-closure-tool","buck2-package-evidence","buck2-portable-toolchain","buck2-portable-toolchain-fixture","buck2-tool-core","buck2-typescript-product","otel-scrape","otelite"]' jq -e --argjson expected "$expected_packages" ' (.packages | map(.name) | sort) == $expected and all(.packages[]; .version == "0.0.0" and .edition == "2021" and .license == "MIT") and diff --git a/scripts/buck2-benchmark/assert-invalidation.mjs b/scripts/buck2-benchmark/assert-invalidation.mjs new file mode 100755 index 000000000..03e99a902 --- /dev/null +++ b/scripts/buck2-benchmark/assert-invalidation.mjs @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +import { readFileSync } from 'node:fs' + +const [rawPath] = process.argv.slice(2) +if (rawPath === undefined) { + console.error('usage: assert-invalidation.mjs RAW_BENCHMARK_JSONL') + process.exit(2) +} + +const records = readFileSync(rawPath, 'utf8') + .split(/\r?\n/u) + .filter((line) => line.trim() !== '') + .map((line) => JSON.parse(line)) +const samples = records.filter( + (record) => record.kind === 'sample' && record.engine === 'buck2' && record.warmup === false, +) + +const assertPhase = ({ phase, expected }) => { + const phaseSamples = samples.filter((sample) => sample.phase === phase) + if (phaseSamples.length === 0) throw new Error(`${phase}: no measured samples`) + for (const sample of phaseSamples) { + if (sample.status !== 'ok' || sample.buckLogStatus !== 'ok') + throw new Error(`${phase}: incomplete action evidence`) + if (expected === 'zero' && sample.actionCount !== 0) + throw new Error(`${phase}: expected zero actions, observed ${sample.actionCount}`) + if (expected === 'positive' && !(sample.actionCount > 0)) + throw new Error(`${phase}: expected at least one action, observed ${sample.actionCount}`) + } +} + +assertPhase({ phase: 'warm-noop', expected: 'zero' }) +assertPhase({ phase: 'mtime-only', expected: 'zero' }) +assertPhase({ phase: 'irrelevant-edit', expected: 'zero' }) +assertPhase({ phase: 'relevant-edit', expected: 'positive' }) +assertPhase({ phase: 'declared-unreachable-edit', expected: 'positive' }) +console.log( + 'buck2 benchmark invalidation assertions: PASS (declared-unreachable production boundary remains coarse)', +) diff --git a/scripts/buck2-benchmark/assert-invalidation.unit.test.mjs b/scripts/buck2-benchmark/assert-invalidation.unit.test.mjs new file mode 100644 index 000000000..5eaf7a266 --- /dev/null +++ b/scripts/buck2-benchmark/assert-invalidation.unit.test.mjs @@ -0,0 +1,69 @@ +import assert from 'node:assert/strict' +import { spawnSync } from 'node:child_process' +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { describe, it } from 'node:test' + +const sample = ({ phase, actionCount }) => ({ + kind: 'sample', + engine: 'buck2', + warmup: false, + phase, + status: 'ok', + buckLogStatus: 'ok', + actionCount, +}) + +const validRecords = [ + sample({ phase: 'warm-noop', actionCount: 0 }), + sample({ phase: 'mtime-only', actionCount: 0 }), + sample({ phase: 'irrelevant-edit', actionCount: 0 }), + sample({ phase: 'relevant-edit', actionCount: 1 }), + sample({ phase: 'declared-unreachable-edit', actionCount: 1 }), +] + +const runAssertion = (records) => { + const directory = mkdtempSync(join(tmpdir(), 'buck2-invalidation-assertion-test-')) + try { + const input = join(directory, 'raw.jsonl') + writeFileSync(input, records.map((record) => JSON.stringify(record)).join('\n') + '\n') + return spawnSync( + process.execPath, + [join(import.meta.dirname, 'assert-invalidation.mjs'), input], + { encoding: 'utf8' }, + ) + } finally { + rmSync(directory, { recursive: true, force: true }) + } +} + +describe('Buck invalidation assertions', () => { + it('accepts role exclusion while explicitly recording the coarse declared-input boundary', () => { + const result = runAssertion(validRecords) + assert.equal(result.status, 0, result.stderr) + assert.match(result.stdout, /declared-unreachable production boundary remains coarse/u) + }) + + it('rejects a false claim that a declared-unreachable production input is fine-grained', () => { + const records = structuredClone(validRecords) + const declaredUnreachable = records.find( + (record) => record.phase === 'declared-unreachable-edit', + ) + assert.ok(declaredUnreachable) + declaredUnreachable.actionCount = 0 + const result = runAssertion(records) + assert.notEqual(result.status, 0) + assert.match(result.stderr, /declared-unreachable-edit: expected at least one action/u) + }) + + it('rejects invalidation from a role-excluded test input', () => { + const records = structuredClone(validRecords) + const roleExcluded = records.find((record) => record.phase === 'irrelevant-edit') + assert.ok(roleExcluded) + roleExcluded.actionCount = 1 + const result = runAssertion(records) + assert.notEqual(result.status, 0) + assert.match(result.stderr, /irrelevant-edit: expected zero actions/u) + }) +}) diff --git a/scripts/buck2-benchmark/benchmark.mjs b/scripts/buck2-benchmark/benchmark.mjs index 4774b103d..be29a9e41 100755 --- a/scripts/buck2-benchmark/benchmark.mjs +++ b/scripts/buck2-benchmark/benchmark.mjs @@ -16,14 +16,20 @@ import { writeFileSync, } from 'node:fs' import { cpus, freemem, platform, release, tmpdir, totalmem } from 'node:os' -import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path' +import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path' import { performance } from 'node:perf_hooks' -import { countNonEmptyLines, parseMaterializations, summarizeSamples } from './lib.mjs' +import { + assertBuckInvalidation, + countNonEmptyLines, + parseMaterializations, + summarizeSamples, +} from './lib.mjs' const schema = 'effect-utils-buck2-benchmark/v0' const defaultRelevantPath = 'packages/@overeng/tui-core/src/mod.ts' const defaultIrrelevantPath = 'context/dependency-materialization/intuition.md' +const defaultDeclaredUnreachablePath = null const fail = (message) => { console.error(message) @@ -44,14 +50,20 @@ const parseArgs = (argv) => { runs: 7, warmups: 2, target: null, + targetPlatform: null, workContract: null, declareEquivalentWork: false, buckIncrementalOnly: false, + assertBuckInvalidation: false, + expectedRelevantActions: null, isolationDir: 'effect-utils-benchmark', relevantPath: defaultRelevantPath, irrelevantPath: defaultIrrelevantPath, + declaredUnreachablePath: defaultDeclaredUnreachablePath, output: null, buckBin: process.env.BUCK2_BENCH_BUCK_BIN ?? null, + buckConfig: [], + buckConfigFiles: [], hostLabel: process.env.BUCK2_BENCH_HOST_LABEL ?? 'redacted-local', } @@ -69,14 +81,21 @@ const parseArgs = (argv) => { else if (arg === '--runs') options.runs = parsePositiveInteger(arg, take()) else if (arg === '--warmups') options.warmups = parsePositiveInteger(arg, take()) else if (arg === '--buck-target') options.target = take() + else if (arg === '--buck-target-platform') options.targetPlatform = take() else if (arg === '--work-contract') options.workContract = take() else if (arg === '--declare-equivalent-work') options.declareEquivalentWork = true else if (arg === '--buck-incremental-only') options.buckIncrementalOnly = true + else if (arg === '--assert-buck-invalidation') options.assertBuckInvalidation = true + else if (arg === '--expected-relevant-actions') + options.expectedRelevantActions = parsePositiveInteger(arg, take()) else if (arg === '--isolation-dir') options.isolationDir = take() else if (arg === '--relevant-path') options.relevantPath = take() else if (arg === '--irrelevant-path') options.irrelevantPath = take() + else if (arg === '--declared-unreachable-path') options.declaredUnreachablePath = take() else if (arg === '--output') options.output = take() else if (arg === '--buck-bin') options.buckBin = take() + else if (arg === '--buck-config') options.buckConfig.push(take()) + else if (arg === '--buck-config-file') options.buckConfigFiles.push(take()) else if (arg === '--host-label') options.hostLabel = take() else if (arg === '--help') { console.log(`usage: node benchmark.mjs [options] @@ -89,13 +108,20 @@ Defaults to a non-executing dry run. Use --execute to run commands. --runs N measured samples per repeatable phase (default: 7) --warmups N warmup samples (default: 2) --buck-target LABEL explicit Buck target under measurement + --buck-target-platform LABEL configured Buck target platform --work-contract ID stable ID for the reviewed workload relationship --declare-equivalent-work assert the contract covers equivalent work (off by default) --buck-incremental-only skip Devenv and destructive cold/restart Buck phases + --assert-buck-invalidation require exact warm/edit action evidence + --expected-relevant-actions N exact actions for each relevant edit --buck-bin PATH pinned Buck2 executable + --buck-config KEY=VALUE Buck config value (repeatable) + --buck-config-file PATH immutable Buck config file (repeatable) --isolation-dir NAME Buck daemon/cache namespace --relevant-path PATH source mutation path --irrelevant-path PATH non-input mutation path + --declared-unreachable-path PATH + declared production input not reachable from the entrypoint --output PATH raw JSONL output --host-label LABEL non-sensitive operator-supplied host label`) process.exit(0) @@ -106,6 +132,8 @@ Defaults to a non-executing dry run. Use --execute to run commands. fail('--execute requires --buck-target; there is no comparable default') if (options.execute === true && options.workContract === null) fail('--execute requires --work-contract; the workload relationship must be named') + if (options.assertBuckInvalidation === true && options.expectedRelevantActions === null) + fail('--assert-buck-invalidation requires --expected-relevant-actions') return options } @@ -215,6 +243,7 @@ const plan = [ ['buck2', 'workspace-check', 'daemon-restart-cache-warm'], ['buck2', 'workspace-check', 'mtime-only', 'mtime'], ['buck2', 'workspace-check', 'relevant-edit', 'relevant'], + ['buck2', 'workspace-check', 'declared-unreachable-edit', 'declared-unreachable'], ['buck2', 'workspace-check', 'irrelevant-edit', 'irrelevant'], ] @@ -267,6 +296,12 @@ const main = async () => { ? 'undeclared' : 'work-contract-declares-no-equivalent-devenv-lane', } + const appendRelevantMutation = (path, index) => { + const probe = `Buck2BenchmarkProbe${index}` + if (extname(path) === '.rs') + appendFileSync(path, `\npub type ${probe} = &'static str; // ${runId}\n`) + else appendFileSync(path, `\nexport type ${probe} = '${runId}'\n`) + } const env = { ...process.env, CI: '1', DEVENV_TUI: 'false' } const emitSkip = ({ @@ -368,6 +403,7 @@ const main = async () => { buck2Requested: options.buckBin, }, target: options.target, + targetPlatform: options.targetPlatform, comparison: { summaryGenerated: false, verdict: 'no-verdict', @@ -380,6 +416,7 @@ const main = async () => { }, mutationPaths: { relevant: options.relevantPath, + declaredUnreachable: options.declaredUnreachablePath, irrelevant: options.irrelevantPath, }, }) @@ -681,6 +718,9 @@ const main = async () => { '--isolation-dir', options.isolationDir, 'build', + ...options.buckConfig.flatMap((value) => ['-c', value]), + ...options.buckConfigFiles.flatMap((path) => ['--config-file', path]), + ...(options.targetPlatform === null ? [] : ['--target-platforms', options.targetPlatform]), options.target, '--local-only', '--no-remote-cache', @@ -786,8 +826,7 @@ const main = async () => { phase: 'relevant-edit', mutation: 'relevant', path: options.relevantPath, - mutate: (path, index) => - appendFileSync(path, `\nexport type Buck2BenchmarkProbe${index} = '${runId}'\n`), + mutate: appendRelevantMutation, command: 'devenv', args: computeOnly, }) @@ -925,11 +964,33 @@ const main = async () => { phase: 'relevant-edit', mutation: 'relevant', path: options.relevantPath, - mutate: (path, index) => - appendFileSync(path, `\nexport type Buck2BenchmarkProbe${index} = '${runId}'\n`), + mutate: appendRelevantMutation, command: buckBin, args: (stem) => makeBuckArgs(stem), }) + if (options.declaredUnreachablePath === null) { + emitSkip({ + engine: 'buck2', + surface: 'workspace-check', + phase: 'declared-unreachable-edit', + mutation: 'declared-unreachable', + reason: 'declared-unreachable-path-undeclared', + }) + } else + await mutationSeries({ + engine: 'buck2', + surface: 'workspace-check', + phase: 'declared-unreachable-edit', + mutation: 'declared-unreachable', + path: options.declaredUnreachablePath, + mutate: (path, index) => + appendFileSync( + path, + `\nexport type Buck2DeclaredUnreachableBenchmarkProbe${index} = '${runId}'\n`, + ), + command: buckBin, + args: (stem) => makeBuckArgs(stem), + }) await mutationSeries({ engine: 'buck2', surface: 'workspace-check', @@ -950,6 +1011,27 @@ const main = async () => { phase: 'final', state: cacheState(worktree, options.isolationDir), }) + if (options.assertBuckInvalidation === true) { + assertBuckInvalidation({ + records: writer.records, + runs: options.runs, + expectedRelevantActions: options.expectedRelevantActions, + }) + writer.write({ + ...baseRecord, + kind: 'assertion', + assertion: 'buck-invalidation', + status: 'ok', + verdict: 'verified', + expected: { + warmActions: 0, + warmMaterializations: 0, + irrelevantActions: 0, + irrelevantMaterializations: 0, + relevantActions: options.expectedRelevantActions, + }, + }) + } } finally { cleanup() } diff --git a/scripts/buck2-benchmark/dry-run.integration.test.mjs b/scripts/buck2-benchmark/dry-run.integration.test.mjs index 19f9dac36..712dd3adf 100644 --- a/scripts/buck2-benchmark/dry-run.integration.test.mjs +++ b/scripts/buck2-benchmark/dry-run.integration.test.mjs @@ -31,7 +31,7 @@ describe('buck2 benchmark dry run', () => { assert.equal(result.status, 0, result.stderr) const records = parseJsonl(readFileSync(output, 'utf8')) const samples = records.filter((record) => record.kind === 'sample') - assert.equal(samples.length, 13) + assert.equal(samples.length, 14) assert.ok(samples.every((record) => record.status === 'skipped')) assert.ok(samples.every((record) => record.verdict === 'no-verdict')) assert.ok(records.some((record) => record.kind === 'cleanup' && record.status === 'ok')) diff --git a/scripts/buck2-megarepo-product-e2e.sh b/scripts/buck2-megarepo-product-e2e.sh new file mode 100755 index 000000000..33db59ac2 --- /dev/null +++ b/scripts/buck2-megarepo-product-e2e.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="${1:?usage: buck2-megarepo-product-e2e.sh REPO_ROOT LAUNCHER TARGET [BUCK_ARGS...]}" +launcher="${2:?launcher is required}" +target="${3:?target is required}" +shift 3 +quality_target="${target%:*}:mr_quality" +awk_bin="${AWK_BIN:?AWK_BIN is required}" +cp_bin="${CP_BIN:?CP_BIN is required}" +dd_bin="${DD_BIN:?DD_BIN is required}" +grep_bin="${GREP_BIN:?GREP_BIN is required}" +jq_bin="${JQ_BIN:?JQ_BIN is required}" +mktemp_bin="${MKTEMP_BIN:?MKTEMP_BIN is required}" +nix_bin="${NIX_BIN:?NIX_BIN is required}" +rm_bin="${RM_BIN:?RM_BIN is required}" +included_non_src="$repo_root/packages/@overeng/tui-react/test/unit/tree.test.tsx" +red_log="$($mktemp_bin)" +source_backup="$($mktemp_bin)" +tampered_artifact="$($mktemp_bin)" +source_mutated=0 +"$cp_bin" --preserve=mode,timestamps "$included_non_src" "$source_backup" +cleanup() { + if [ "$source_mutated" = 1 ]; then "$cp_bin" --preserve=mode,timestamps "$source_backup" "$included_non_src"; fi + "$rm_bin" -f "$red_log" "$source_backup" "$tampered_artifact" +} +trap cleanup EXIT +run_id="megarepo-product-e2e-$$-$RANDOM" +output="$($launcher --evidence-dir "$repo_root/tmp/buck2-evidence" --run-id "$run_id" --print-command -- build "$target" "$target[descriptor]" "$quality_target" "$@" --show-full-output --local-only --no-remote-cache)" +artifact="$(printf '%s\n' "$output" | "$awk_bin" -v label="root${target}" '$1 == label { print $2 }')" +descriptor="$(printf '%s\n' "$output" | "$awk_bin" -v label="root${target}[descriptor]" '$1 == label { print $2 }')" +[ -f "$artifact" ] && [ -f "$descriptor" ] || { echo "megarepo product outputs are missing" >&2; exit 1; } +echo "buck2-megarepo-product-e2e: QUALITY PASS target=$quality_target" + +source_mutated=1 +printf '\nconst buck2IncludedNonSrcRed: never = 1\n' >>"$included_non_src" +: >"$red_log" +if "$launcher" --evidence-dir "$repo_root/tmp/buck2-evidence" --run-id "$run_id-included-non-src-red" --print-command -- build "$quality_target" "$@" --local-only --no-remote-cache >"$red_log" 2>&1; then + echo "mr_quality accepted an invalid included non-src project file" >&2 + exit 1 +fi +"$grep_bin" -E "TS2322|not assignable" "$red_log" >/dev/null || { echo "included non-src RED missed its asserted typecheck seam" >&2; exit 1; } +"$cp_bin" --preserve=mode,timestamps "$source_backup" "$included_non_src" +source_mutated=0 +"$launcher" --evidence-dir "$repo_root/tmp/buck2-evidence" --run-id "$run_id-included-non-src-green" --print-command -- build "$quality_target" "$@" --local-only --no-remote-cache >/dev/null +echo "buck2-megarepo-product-e2e: INCLUDED NON-SRC RED/GREEN PASS path=packages/@overeng/tui-react/test/unit/tree.test.tsx" + +export BUCK2_PRODUCT_DESCRIPTOR="$descriptor" +export BUCK2_PRODUCT_CONTRACT="$repo_root/nix/workspace-tools/lib/buck2-build-product-contract.nix" +canonical="$($nix_bin eval --impure --raw --expr ' + let contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + descriptor = builtins.fromJSON (builtins.readFile (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR")); + in contract.canonicalDescriptorJson descriptor +')" +[ "$canonical" = "$($jq_bin -c -S . "$descriptor")" ] || { echo "emitter descriptor is not canonical under the Nix contract" >&2; exit 1; } +if "$nix_bin" eval --impure --raw --expr ' + let contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + descriptor = builtins.fromJSON (builtins.readFile (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR")); + in contract.canonicalDescriptorJson (descriptor // { unknownEmitterField = true; }) +' >/dev/null 2>&1; then + echo "Nix contract accepted an unknown emitter field" >&2 + exit 1 +fi + +echo "buck2-megarepo-product-e2e: CONTRACT PASS artifact=$artifact descriptor=$descriptor" +export BUCK2_PRODUCT_ARTIFACT_STORE="$($nix_bin store add --mode flat --name artifact.tar "$artifact")" +export BUCK2_PRODUCT_DESCRIPTOR_STORE="$($nix_bin store add --mode flat --name descriptor.json "$descriptor")" +export BUCK2_PRODUCT_IMPORTER="$repo_root/nix/workspace-tools/lib/buck2-artifact-import.nix" +export BUCK2_PRODUCT_NIXPKGS="${BUCK2_PRODUCT_NIXPKGS:?BUCK2_PRODUCT_NIXPKGS must name the pinned nixpkgs store path}" +if "$nix_bin" build --impure --no-link --expr ' + let + pkgs = import (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_NIXPKGS")) { system = builtins.currentSystem; }; + contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + importArtifact = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_IMPORTER")) { inherit pkgs; }; + descriptor = builtins.fromJSON (builtins.readFile (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR_STORE"))); + in importArtifact { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = descriptor.platform // { architecture = "intentional-red"; }; + artifact = builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_ARTIFACT_STORE"); + } +' >/dev/null 2>"$red_log"; then + echo "importer accepted an independently mismatched platform" >&2 + exit 1 +fi +"$grep_bin" -F "platform mismatch" "$red_log" >/dev/null || { echo "platform RED missed its asserted seam" >&2; exit 1; } +echo "buck2-megarepo-product-e2e: PLATFORM RED PASS" + +"$cp_bin" "$artifact" "$tampered_artifact" +printf '\377' | "$dd_bin" of="$tampered_artifact" bs=1 seek=0 conv=notrunc status=none +export BUCK2_PRODUCT_TAMPERED_ARTIFACT_STORE="$($nix_bin store add --mode flat --name tampered-artifact.tar "$tampered_artifact")" +: >"$red_log" +if "$nix_bin" build --impure --no-link --expr ' + let + pkgs = import (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_NIXPKGS")) { system = builtins.currentSystem; }; + contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + importArtifact = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_IMPORTER")) { inherit pkgs; }; + descriptor = builtins.fromJSON (builtins.readFile (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR_STORE"))); + in importArtifact { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = { os = "linux"; architecture = "x86_64"; abi = "glibc"; }; + artifact = builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_TAMPERED_ARTIFACT_STORE"); + } +' >/dev/null 2>"$red_log"; then + echo "importer accepted a tampered payload" >&2 + exit 1 +fi +"$grep_bin" -F "payload digest mismatch" "$red_log" >/dev/null || { echo "payload RED missed its asserted seam" >&2; exit 1; } +echo "buck2-megarepo-product-e2e: PAYLOAD RED PASS" + +: >"$red_log" +if "$nix_bin" build --impure --no-link --expr ' + let + pkgs = import (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_NIXPKGS")) { system = builtins.currentSystem; }; + contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + importArtifact = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_IMPORTER")) { inherit pkgs; }; + original = builtins.fromJSON (builtins.readFile (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR_STORE"))); + descriptor = original // { runtime = original.runtime // { machine = "intentional-red"; }; }; + in importArtifact { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = { os = "linux"; architecture = "x86_64"; abi = "glibc"; }; + artifact = builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_ARTIFACT_STORE"); + } +' >/dev/null 2>"$red_log"; then + echo "importer accepted mismatched observed runtime facts" >&2 + exit 1 +fi +"$grep_bin" -F "ELF machine mismatch" "$red_log" >/dev/null || { echo "runtime RED missed its asserted seam" >&2; exit 1; } +echo "buck2-megarepo-product-e2e: RUNTIME RED PASS" + +imported="$($nix_bin build --impure --no-link --print-out-paths --expr ' + let + pkgs = import (builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_NIXPKGS")) { system = builtins.currentSystem; }; + contract = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_CONTRACT")); + importArtifact = import (builtins.toPath (builtins.getEnv "BUCK2_PRODUCT_IMPORTER")) { inherit pkgs; }; + descriptorPath = builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_DESCRIPTOR_STORE"); + descriptor = builtins.fromJSON (builtins.readFile descriptorPath); + in importArtifact { + inherit descriptor; + expectedDescriptorDigest = contract.descriptorDigest descriptor; + expectedPlatform = { os = "linux"; architecture = "x86_64"; abi = "glibc"; }; + artifact = builtins.storePath (builtins.getEnv "BUCK2_PRODUCT_ARTIFACT_STORE"); + } +')" +runtime_output="$(env -i PATH=/nonexistent "$imported/bin/mr" --version)" +[ -n "$runtime_output" ] || { echo "imported mr runtime smoke produced no version" >&2; exit 1; } +echo "buck2-megarepo-product-e2e: RUNTIME PASS imported=$imported" diff --git a/scripts/buck2-otel-scrape-nix-admission.sh b/scripts/buck2-otel-scrape-nix-admission.sh new file mode 100644 index 000000000..39c055445 --- /dev/null +++ b/scripts/buck2-otel-scrape-nix-admission.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +set -euo pipefail + +mode="${1:?usage: buck2-otel-scrape-nix-admission.sh smoke|admit STAGE0_CONFIG TOOLCHAIN_CONFIG}" +stage0_config="${2:?stage-0 config is required}" +toolchain_config="${3:?toolchain config is required}" +repo_root="${DEVENV_ROOT:-$PWD}" +buck2_bin="${BUCK2_BIN:?BUCK2_BIN is required}" +nix_bin="${NIX_BIN:?NIX_BIN is required}" +jq_bin="${JQ_BIN:?JQ_BIN is required}" +awk_bin="${AWK_BIN:?AWK_BIN is required}" +isolation="otel-scrape-nix-admission-$$-$RANDOM" +fixture_root="$(mktemp -d "${TMPDIR:-/tmp}/otel-scrape-nix-admission.XXXXXX")" +case "$mode" in + smoke) + expected_descriptor_digest="" + ;; + admit) + expected_descriptor_digest="${BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST:?admission requires externally supplied BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST}" + ;; + *) + echo "buck2:otel-scrape:nix-admission: mode must be smoke or admit" >&2 + exit 64 + ;; +esac +cleanup() { + "$buck2_bin" --isolation-dir "$isolation" kill >/dev/null 2>&1 || true + rm -rf -- "$fixture_root" +} +trap cleanup EXIT + +buck_output="$($buck2_bin \ + --isolation-dir "$isolation" \ + build \ + --config-file "$stage0_config" \ + --config-file "$toolchain_config" \ + --target-platforms //buck2/platforms:target_x86_64_linux_musl_static \ + //packages/@overeng/otel-scrape:product \ + '//packages/@overeng/otel-scrape:product[descriptor]' \ + --show-full-output --local-only --no-remote-cache)" +archive="$(printf '%s\n' "$buck_output" | "$awk_bin" \ + '$1 == "root//packages/@overeng/otel-scrape:product" { print $2 }')" +descriptor="$(printf '%s\n' "$buck_output" | "$awk_bin" \ + '$1 == "root//packages/@overeng/otel-scrape:product[descriptor]" { print $2 }')" +[ -f "$archive" ] && [ -f "$descriptor" ] || { + echo "buck2:otel-scrape:nix-admission: Buck omitted the exact product pair" >&2 + exit 1 +} + +export BUCK2_OTEL_PRODUCT_ARCHIVE="$archive" +export BUCK2_OTEL_PRODUCT_DESCRIPTOR="$descriptor" +export BUCK2_OTEL_PRODUCT_REPO="$repo_root" +descriptor_digest_expr='let + repo = builtins.toPath (builtins.getEnv "BUCK2_OTEL_PRODUCT_REPO"); + contract = import (repo + "/nix/workspace-tools/lib/buck2-build-product-contract.nix"); + descriptor = builtins.fromJSON (builtins.readFile (builtins.getEnv "BUCK2_OTEL_PRODUCT_DESCRIPTOR")); +in contract.descriptorDigest descriptor' +if [ "$mode" = smoke ]; then + expected_descriptor_digest="$($nix_bin eval --impure --raw --expr "$descriptor_digest_expr")" +fi +export BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST="$expected_descriptor_digest" + +import_expr='let + repo = builtins.toPath (builtins.getEnv "BUCK2_OTEL_PRODUCT_REPO"); + pkgs = import (builtins.getFlake (toString repo)).inputs.nixpkgs { system = builtins.currentSystem; }; + importArtifact = import (repo + "/nix/workspace-tools/lib/buck2-artifact-import.nix") { inherit pkgs; }; + descriptor = builtins.fromJSON (builtins.readFile (builtins.getEnv "BUCK2_OTEL_PRODUCT_DESCRIPTOR")); + artifact = builtins.path { path = builtins.getEnv "BUCK2_OTEL_PRODUCT_ARCHIVE"; name = "otel-scrape-buck-product.tar"; }; +in importArtifact { + inherit artifact descriptor; + expectedDescriptorDigest = builtins.getEnv "BUCK2_OTEL_EXPECTED_DESCRIPTOR_DIGEST"; + expectedPlatform = { os = "linux"; architecture = "x86_64"; abi = "musl"; }; +}' + +substituted_descriptor="$fixture_root/descriptor.substituted.json" +"$jq_bin" -c '.semanticProvenance.recipe += "-substituted"' "$descriptor" >"$substituted_descriptor" +export BUCK2_OTEL_PRODUCT_DESCRIPTOR="$substituted_descriptor" +red_log="$fixture_root/substitution-red.log" +if "$nix_bin" build --impure --no-link --expr "$import_expr" >"$red_log" 2>&1; then + echo "buck2:otel-scrape:nix-admission: substituted descriptor retained admission" >&2 + exit 1 +fi +grep -F "descriptor digest mismatch" "$red_log" >/dev/null || { + echo "buck2:otel-scrape:nix-admission: substitution failed outside descriptor identity seam" >&2 + sed -n '1,120p' "$red_log" >&2 + exit 1 +} +echo "buck2:otel-scrape:nix-admission: RED descriptor substitution" + +export BUCK2_OTEL_PRODUCT_DESCRIPTOR="$descriptor" +imported="$($nix_bin build --impure --no-link --print-out-paths --expr "$import_expr")" +[ -x "$imported/bin/otel-scrape" ] +"$jq_bin" -e ' + .semanticProvenance.target == "root//packages/@overeng/otel-scrape:product" and + .runtime == {kind: "self-contained", inspectionContract: "elf-static/v1"} +' "$imported/share/buck-build-product/descriptor.json" >/dev/null +echo "buck2:otel-scrape:nix-admission: GREEN mode=$mode digest=$expected_descriptor_digest" diff --git a/toolchains/BUCK b/toolchains/BUCK index d8d1cd06d..558cf47a3 100644 --- a/toolchains/BUCK +++ b/toolchains/BUCK @@ -1,4 +1,9 @@ load(":configured.bzl", "configured_exec") +load("@prelude//tests:test_toolchain.bzl", "noop_test_toolchain") +load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain") +load("@prelude//toolchains:remote_test_execution.bzl", "remote_test_execution_toolchain") +load("@root//buck2/toolchains:nix_local.bzl", "nix_local_rust_cxx_python_toolchains") +load("@root//buck2/toolchains:conventional_probe.bzl", "conventional_toolchain_probe") # Nix is the stage-0 authority. Each literal immutable path participates in the # configured graph and therefore in every consuming action key. @@ -8,12 +13,34 @@ configured_exec( visibility = ["PUBLIC"], ) +# Prelude Rust compilation and linking consume both conventional providers, +# but only Rust product invocations supply that independently rooted config. +# The macro is a no-op without it, so stage-0 and TypeScript-only graphs do not +# accidentally acquire a Rust/Nix dependency merely by loading this package. +nix_local_rust_cxx_python_toolchains() + +conventional_toolchain_probe( + name = "conventional_rust_cxx_execution_probe", + toolchain_identity = read_config("rust_toolchain", "compile_identity", ""), + visibility = ["PUBLIC"], +) + +system_genrule_toolchain(name = "genrule", visibility = ["PUBLIC"]) +noop_test_toolchain(name = "test", visibility = ["PUBLIC"]) +remote_test_execution_toolchain(name = "remote_test_execution", visibility = ["PUBLIC"]) + configured_exec( name = "package_evidence_tool", path = read_config("buck2_stage0", "package_evidence_tool", ""), visibility = ["PUBLIC"], ) +configured_exec( + name = "typescript_product_tool", + path = read_config("buck2_stage0", "typescript_product_tool", ""), + visibility = ["PUBLIC"], +) + configured_exec( name = "portable_toolchain", path = read_config("buck2_stage0", "portable_toolchain", ""),